require 'spec_helper' require 'fixtures/middleware/public_info_setter' require 'fixtures/middleware/internal_info_setter' describe Bugsnag::MiddlewareStack do it "runs before_bugsnag_notify callbacks, adding a tab" do callback_run_count = 0 Bugsnag.before_notify_callbacks << lambda {|notif| notif.add_tab(:some_tab, { :info => "here", :data => "also here" }) callback_run_count += 1 } Bugsnag.notify(BugsnagTestException.new("It crashed")) expect(callback_run_count).to eq(1) expect(Bugsnag).to have_sent_notification{ |payload, headers| event = get_event_from_payload(payload) expect(event["metaData"]["some_tab"]).not_to be_nil expect(event["metaData"]["some_tab"]["info"]).to eq("here") expect(event["metaData"]["some_tab"]["data"]).to eq("also here") } end it "runs before_bugsnag_notify callbacks, adding custom data" do callback_run_count = 0 Bugsnag.before_notify_callbacks << lambda {|notif| notif.add_tab(:custom, {info: "here"}) notif.add_tab(:custom, {data: "also here"}) callback_run_count += 1 } Bugsnag.notify(BugsnagTestException.new("It crashed")) expect(callback_run_count).to eq(1) expect(Bugsnag).to have_sent_notification{ |payload, headers| event = get_event_from_payload(payload) expect(event["metaData"]["custom"]).not_to be_nil expect(event["metaData"]["custom"]["info"]).to eq("here") expect(event["metaData"]["custom"]["data"]).to eq("also here") } end it "runs before_bugsnag_notify callbacks, setting the user" do callback_run_count = 0 Bugsnag.before_notify_callbacks << lambda {|notif| notif.user = {:id => "here", :email => "also here", :name => "also here too", :random_key => "also here too too"} callback_run_count += 1 } Bugsnag.notify(BugsnagTestException.new("It crashed")) expect(callback_run_count).to eq(1) expect(Bugsnag).to have_sent_notification{ |payload, headers| event = get_event_from_payload(payload) expect(event["user"]).not_to be_nil expect(event["user"]["id"]).to eq("here") expect(event["user"]["email"]).to eq("also here") expect(event["user"]["name"]).to eq("also here too") expect(event["user"]["random_key"]).to eq("also here too too") } end it "allows block to override values set by internal middleware" do Bugsnag.configuration.internal_middleware.use(InternalInfoSetter) Bugsnag.notify(BugsnagTestException.new("It crashed")) do |report| report.meta_data.merge!({custom: {info: 'overridden'}}) end expect(Bugsnag).to have_sent_notification{ |payload, headers| event = get_event_from_payload(payload) expect(event["metaData"]["custom"]).not_to be_nil expect(event["metaData"]["custom"]["info"]).to eq("overridden") } end it "allows block to override public middleware" do Bugsnag.configuration.middleware.use(PublicInfoSetter) Bugsnag.notify(BugsnagTestException.new("It crashed")) do |report| report.meta_data.merge!({custom: {info: 'overridden'}}) end expect(Bugsnag).to have_sent_notification{ |payload, headers| event = get_event_from_payload(payload) expect(event["metaData"]["custom"]).not_to be_nil expect(event["metaData"]["custom"]["info"]).to eq("overridden") } end it "does not have have before callbacks by default" do expect(Bugsnag.before_notify_callbacks.size).to eq(0) Bugsnag.notify(BugsnagTestException.new("It crashed")) expect(Bugsnag).to have_sent_notification{ |payload, headers| event = get_event_from_payload(payload) expect(event["metaData"].size).to eq(0) } end it "does not execute disabled bugsnag middleware" do callback_run_count = 0 Bugsnag.configure do |config| config.middleware.disable(Bugsnag::Middleware::Callbacks) end Bugsnag.before_notify_callbacks << lambda {|notif| callback_run_count += 1 } Bugsnag.notify(BugsnagTestException.new("It crashed")) expect(callback_run_count).to eq(0) end it "does not notify if a callback told so" do Bugsnag.before_notify_callbacks << lambda do |notif| notif.ignore! end Bugsnag.notify(BugsnagTestException.new("It crashed")) expect(Bugsnag).not_to have_sent_notification end it "allows inspection of meta_data before ignoring exception" do # Use before notify callbacks as only the callback based metadata is # available to before_notify_callbacks Bugsnag.before_notify_callbacks << lambda do |notif| notif.add_tab(:sidekiq, {:retry_count => 4}) end Bugsnag.before_notify_callbacks << lambda do |notif| notif.ignore! if notif.meta_data[:sidekiq][:retry_count] > 3 end Bugsnag.notify(BugsnagTestException.new("It crashed")) expect(Bugsnag).not_to have_sent_notification end it "allows meta_data to be modified in a middleware" do MetaDataAdder = Class.new do def initialize(bugsnag) @bugsnag = bugsnag end def call(report) report.meta_data = {test: {value: "abcdef123456abcdef123456abcdef123456"}} @bugsnag.call(report) end end MetaDataMunger = Class.new do def initialize(bugsnag) @bugsnag = bugsnag end def call(report) token = report.meta_data[:test][:value] report.meta_data[:test][:value] = "#{token[0...6]}*****#{token[-4..-1]}" @bugsnag.call(report) end end Bugsnag.configure do |c| c.middleware.use MetaDataAdder c.middleware.use MetaDataMunger end Bugsnag.notify(BugsnagTestException.new("It crashed")) expect(Bugsnag).to have_sent_notification{ |payload, headers| event = get_event_from_payload(payload) expect(event["metaData"]['test']['value']).to eq("abcdef*****3456") } end if ruby_version_greater_equal?("2.3.0") context "with a ruby version >= 2.3.0" do it "attaches did you mean metadata when necessary" do begin "Test".prepnd "T" rescue Exception => e Bugsnag.notify(e) end expect(Bugsnag).to have_sent_notification{ |payload, headers| event = get_event_from_payload(payload) expect(event["metaData"]["error"]).to_not be_nil expect(event["metaData"]["error"]).to eq({"suggestion" => "prepend"}) } end end end context "with a ruby version < 2.3.0" do if !ruby_version_greater_equal?("2.3.0") it "doesn't attach did you mean metadata" do begin "Test".prepnd "T" rescue Exception => e Bugsnag.notify(e) end expect(Bugsnag).to have_sent_notification{ |payload, headers| event = get_event_from_payload(payload) expect(event["metaData"]["error"]).to be_nil } end end end it "doesn't allow handledState properties to be changed in middleware" do HandledStateChanger = Class.new do def initialize(bugsnag) @bugsnag = bugsnag end def call(report) report.severity_reason = { :test => "test" } @bugsnag.call(report) end end Bugsnag.configure do |c| c.middleware.use HandledStateChanger end Bugsnag.notify(BugsnagTestException.new("It crashed"), true) do |report| report.severity_reason = { :type => "middleware_handler", :attributes => { :name => "middleware_test" } } end expect(Bugsnag).to have_sent_notification{ |payload, headers| event = get_event_from_payload(payload) expect(event["unhandled"]).to be true expect(event["severityReason"]).to eq({ "type" => "middleware_handler", "attributes" => { "name" => "middleware_test" } }) } end end