diff --git a/.rubocop.yml b/.rubocop.yml index 368f7ecbe..8c79cfeb8 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -5,6 +5,9 @@ AllCops: - 'lib/raven/okjson.rb' - 'lib/raven/backports/uri.rb' -Lint/UnusedMethodArgument: - Exclude: +Lint/UnusedMethodArgument: + Exclude: - 'lib/raven/backports/uri.rb' + +Style/SignalException: + Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index a482349e7..9b4c8dcb5 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -353,22 +353,6 @@ Style/Semicolon: - 'lib/raven/processor/removecircularreferences.rb' - 'lib/raven/processor/sanitizedata.rb' -# Offense count: 47 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -Style/SignalException: - Exclude: - - 'lib/raven/client.rb' - - 'lib/raven/configuration.rb' - - 'lib/raven/event.rb' - - 'lib/raven/integrations/rails/active_job.rb' - - 'lib/raven/processor.rb' - - 'lib/raven/transports.rb' - - 'lib/raven/transports/udp.rb' - - 'spec/raven/event_spec.rb' - - 'spec/raven/integrations/rack_spec.rb' - - 'spec/raven/raven_spec.rb' - # Offense count: 1 # Configuration parameters: Methods. Style/SingleLineBlockParams: diff --git a/.travis.yml b/.travis.yml index db3751160..aa2eae50f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,3 +34,7 @@ matrix: gemfile: gemfiles/rails42.gemfile - rvm: ree gemfile: gemfiles/rails41.gemfile + - rvm: 2.2.4 + gemfile: gemfiles/rails32.gemfile + - rvm: ruby-head + gemfile: gemfiles/rails32.gemfile diff --git a/lib/raven/client.rb b/lib/raven/client.rb index a97968321..971227189 100644 --- a/lib/raven/client.rb +++ b/lib/raven/client.rb @@ -49,6 +49,20 @@ def send_event(event) event end + def transport + @transport ||= + case configuration.scheme + when 'udp' + Transports::UDP.new(configuration) + when 'http', 'https' + Transports::HTTP.new(configuration) + when 'dummy' + Transports::Dummy.new(configuration) + else + fail "Unknown transport scheme '#{configuration.scheme}'" + end + end + private def configuration_allows_sending @@ -76,18 +90,6 @@ def get_log_message(event) (event && event[:message]) || '' end - def transport - @transport ||= - case configuration.scheme - when 'udp' - Transports::UDP.new(configuration) - when 'http', 'https' - Transports::HTTP.new(configuration) - else - raise Error, "Unknown transport scheme '#{self.configuration.scheme}'" - end - end - def generate_auth_header now = Time.now.to_i.to_s fields = { diff --git a/lib/raven/transports/dummy.rb b/lib/raven/transports/dummy.rb new file mode 100644 index 000000000..3653b0fa9 --- /dev/null +++ b/lib/raven/transports/dummy.rb @@ -0,0 +1,16 @@ +module Raven + module Transports + class Dummy < Transport + attr_accessor :events + + def initialize(*) + super + @events = [] + end + + def send_event(auth_header, data, options = {}) + @events << [auth_header, data, options] + end + end + end +end diff --git a/sentry-raven.gemspec b/sentry-raven.gemspec index e5127e6da..f66eea590 100644 --- a/sentry-raven.gemspec +++ b/sentry-raven.gemspec @@ -21,6 +21,7 @@ Gem::Specification.new do |gem| gem.add_development_dependency "rake" gem.add_development_dependency "rubocop" if RUBY_VERSION > '1.8.7' gem.add_development_dependency "rspec", "~> 3.0" + gem.add_development_dependency "rspec-rails" gem.add_development_dependency "mime-types", "~> 1.16" gem.add_development_dependency "rest-client", "< 1.7.0" if RUBY_VERSION == '1.8.7' gem.add_development_dependency "rest-client" if RUBY_VERSION > '1.8.7' diff --git a/spec/raven/event_spec.rb b/spec/raven/event_spec.rb index 74186fe18..1c6861112 100644 --- a/spec/raven/event_spec.rb +++ b/spec/raven/event_spec.rb @@ -426,19 +426,19 @@ class Exception < Exception; end end context 'for an excluded exception type' do + module Raven::Test + class BaseExc < Exception; end + class SubExc < BaseExc; end + end + it 'returns nil for a string match' do config = Raven::Configuration.new - config.excluded_exceptions << 'RuntimeError' - expect(Raven::Event.capture_exception(RuntimeError.new, + config.excluded_exceptions << 'Raven::Test::BaseExc' + expect(Raven::Event.capture_exception(Raven::Test::BaseExc.new, :configuration => config)).to be_nil end it 'returns nil for a class match' do - module Raven::Test - class BaseExc < Exception; end - class SubExc < BaseExc; end - end - config = Raven::Configuration.new config.excluded_exceptions << Raven::Test::BaseExc @@ -528,86 +528,6 @@ class SubExc < BaseExc; end end end - context 'in a rails environment' do - before do - rails = double('Rails') - allow(rails).to receive(:root) { '/rails/root' } - stub_const('Rails', rails) - Raven.configure do |config| - config.project_root ||= ::Rails.root - end - end - - context 'with an application stacktrace' do - let(:exception) do - e = Exception.new(message) - allow(e).to receive(:backtrace).and_return([ - "/rails/root/vendor/bundle/cache/other_gem.rb:10:in `public_method'", - "vendor/bundle/some_gem.rb:10:in `a_method'", - "/rails/root/app/models/user.rb:132:in `new_function'", - "/gem/lib/path:87:in `a_function'", - "/app/some/other/path:1412:in `other_function'", - "test/some/other/path:1412:in `other_function'" - ]) - e - end - - it 'marks in_app correctly' do - expect(Raven.configuration.project_root).to eq('/rails/root') - frames = hash[:exception][:values][0][:stacktrace][:frames] - expect(frames[0][:filename]).to eq("test/some/other/path") - expect(frames[0][:in_app]).to eq(true) - expect(frames[1][:filename]).to eq("/app/some/other/path") - expect(frames[1][:in_app]).to eq(false) - expect(frames[2][:filename]).to eq("/gem/lib/path") - expect(frames[2][:in_app]).to eq(false) - expect(frames[3][:filename]).to eq("app/models/user.rb") - expect(frames[3][:in_app]).to eq(true) - expect(frames[4][:filename]).to eq("vendor/bundle/some_gem.rb") - expect(frames[4][:in_app]).to eq(false) - expect(frames[5][:filename]).to eq("vendor/bundle/cache/other_gem.rb") - expect(frames[5][:in_app]).to eq(false) - end - - context 'when an in_app path under project_root is on the load path' do - before do - $LOAD_PATH << '/rails/root/app/models' - end - - after do - $LOAD_PATH.delete('/rails/root/app/models') - end - - it 'normalizes the filename using project_root' do - frames = hash[:exception][:values][0][:stacktrace][:frames] - expect(frames[3][:filename]).to eq("app/models/user.rb") - end - end - - context 'when a non-in_app path under project_root is on the load path' do - before do - $LOAD_PATH << '/rails/root/vendor/bundle' - end - - after do - $LOAD_PATH.delete('/rails/root/vendor/bundle') - end - - it 'normalizes the filename using the load path' do - frames = hash[:exception][:values][0][:stacktrace][:frames] - expect(frames[5][:filename]).to eq("cache/other_gem.rb") - end - end - - context "when a non-in_app path under project_root isn't on the load path" do - it 'normalizes the filename using project_root' do - frames = hash[:exception][:values][0][:stacktrace][:frames] - expect(frames[5][:filename]).to eq("vendor/bundle/cache/other_gem.rb") - end - end - end - end - it "sets the culprit" do expect(hash[:culprit]).to eq("/path/to/some/file in function_name at line 22") end diff --git a/spec/raven/integrations/rails/event_spec.rb b/spec/raven/integrations/rails/event_spec.rb new file mode 100644 index 000000000..289c9fc41 --- /dev/null +++ b/spec/raven/integrations/rails/event_spec.rb @@ -0,0 +1,79 @@ +describe Raven::Event do + context 'in a rails environment' do + before do + Raven.configure do |config| + config.project_root ||= ::Rails.root + end + end + + context 'with an application stacktrace' do + let(:exception) do + e = Exception.new("Oh no!") + allow(e).to receive(:backtrace).and_return([ + "#{Rails.root}/vendor/bundle/cache/other_gem.rb:10:in `public_method'", + "vendor/bundle/some_gem.rb:10:in `a_method'", + "#{Rails.root}/app/models/user.rb:132:in `new_function'", + "/gem/lib/path:87:in `a_function'", + "/app/some/other/path:1412:in `other_function'", + "test/some/other/path:1412:in `other_function'" + ]) + e + end + + let(:hash) { Raven::Event.capture_exception(exception).to_hash } + + it 'marks in_app correctly' do + frames = hash[:exception][:values][0][:stacktrace][:frames] + expect(frames[0][:filename]).to eq("test/some/other/path") + expect(frames[0][:in_app]).to eq(true) + expect(frames[1][:filename]).to eq("/app/some/other/path") + expect(frames[1][:in_app]).to eq(false) + expect(frames[2][:filename]).to eq("/gem/lib/path") + expect(frames[2][:in_app]).to eq(false) + expect(frames[3][:filename]).to eq("app/models/user.rb") + expect(frames[3][:in_app]).to eq(true) + expect(frames[4][:filename]).to eq("vendor/bundle/some_gem.rb") + expect(frames[4][:in_app]).to eq(false) + expect(frames[5][:filename]).to eq("vendor/bundle/cache/other_gem.rb") + expect(frames[5][:in_app]).to eq(false) + end + + context 'when an in_app path under project_root is on the load path' do + before do + $LOAD_PATH << "#{Rails.root}/app/models" + end + + after do + $LOAD_PATH.delete("#{Rails.root}/app/models") + end + + it 'normalizes the filename using project_root' do + frames = hash[:exception][:values][0][:stacktrace][:frames] + expect(frames[3][:filename]).to eq("app/models/user.rb") + end + end + + context 'when a non-in_app path under project_root is on the load path' do + before do + $LOAD_PATH << "#{Rails.root}/vendor/bundle" + end + + after do + $LOAD_PATH.delete("#{Rails.root}/vendor/bundle") + end + + it 'normalizes the filename using the load path' do + frames = hash[:exception][:values][0][:stacktrace][:frames] + expect(frames[5][:filename]).to eq("cache/other_gem.rb") + end + end + + context "when a non-in_app path under project_root isn't on the load path" do + it 'normalizes the filename using project_root' do + frames = hash[:exception][:values][0][:stacktrace][:frames] + expect(frames[5][:filename]).to eq("vendor/bundle/cache/other_gem.rb") + end + end + end + end +end diff --git a/spec/raven/integrations/rails_spec.rb b/spec/raven/integrations/rails_spec.rb new file mode 100644 index 000000000..77065e1db --- /dev/null +++ b/spec/raven/integrations/rails_spec.rb @@ -0,0 +1,24 @@ +require "spec_helper" +require "rspec/rails" +require "raven/transports/dummy" + +describe TestApp, :type => :request do + before(:all) do + Raven.configure do |config| + config.dsn = 'dummy://notaserver' + config.encoding = 'json' + end + + TestApp.initialize! + end + + it "inserts middleware" do + expect(TestApp.middleware).to include(Raven::Rack) + end + + pending "should capture exceptions" do + get "/exception" + expect(response.status).to eq(500) + expect(Raven.client.transport.events.size).to eq(1) + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e913d4dd4..084ebbc19 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,8 @@ require 'raven' +require File.dirname(__FILE__) + "/support/test_rails_app/app.rb" +require "rspec/rails" + RSpec.configure do |config| config.mock_with(:rspec) { |mocks| mocks.verify_partial_doubles = true } config.raise_errors_for_deprecations! @@ -35,7 +38,6 @@ def build_exception_with_two_causes return exception end - def build_exception_with_recursive_cause backtrace = double("Backtrace") allow(backtrace).to receive(:to_a).and_return([]) diff --git a/spec/support/test_rails_app/app.rb b/spec/support/test_rails_app/app.rb new file mode 100644 index 000000000..ba980c6ef --- /dev/null +++ b/spec/support/test_rails_app/app.rb @@ -0,0 +1,40 @@ +require 'rails' +# require "active_model/railtie" +# require "active_job/railtie" +# require "active_record/railtie" +require "action_controller/railtie" +# require "action_mailer/railtie" +require "action_view/railtie" +# require "action_cable/engine" +# require "sprockets/railtie" +# require "rails/test_unit/railtie" +require 'raven/integrations/rails' + +class TestApp < Rails::Application + config.secret_key_base = "test" + + # Usually set for us in production.rb + config.eager_load = true + config.cache_classes = true + config.serve_static_files = false + + config.log_level = :error + config.logger = Logger.new(STDOUT) + + routes.append do + get "/exception", :to => "hello#exception" + root :to => "hello#world" + end +end + +class HelloController < ActionController::Base + def exception + raise "An unhandled exception!" + end + + def world + render :text => "Hello World!" + end +end + +Rails.env = "production"