spec/notification_spec.rb in bugsnag-2.5.1 vs spec/notification_spec.rb in bugsnag-2.6.0

- old
+ new

@@ -26,624 +26,625 @@ java.lang.System.out.printf(nil) end end describe Bugsnag::Notification do - def notify_test_exception(*args) - Bugsnag.notify(RuntimeError.new("test message"), *args) - end - it "should contain an api_key if one is set" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - expect(payload[:apiKey]).to eq("c9d60ae4c7e70c4b6c4ebd3e8056d2b8") - end - Bugsnag.notify(BugsnagTestException.new("It crashed")) + + expect(Bugsnag).to have_sent_notification{ |payload| + expect(payload["apiKey"]).to eq("c9d60ae4c7e70c4b6c4ebd3e8056d2b8") + } end it "does not notify if api_key is not set" do Bugsnag.configuration.api_key = nil - expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload) - Bugsnag.notify(BugsnagTestException.new("It crashed")) + + expect(Bugsnag).not_to have_sent_notification end it "does not notify if api_key is empty" do Bugsnag.configuration.api_key = "" - expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload) - Bugsnag.notify(BugsnagTestException.new("It crashed")) + + expect(Bugsnag).not_to have_sent_notification end it "lets you override the api_key" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - expect(payload[:apiKey]).to eq("9d84383f9be2ca94902e45c756a9979d") - end - Bugsnag.notify(BugsnagTestException.new("It crashed"), :api_key => "9d84383f9be2ca94902e45c756a9979d") + + expect(Bugsnag).to have_sent_notification{ |payload| + expect(payload["apiKey"]).to eq("9d84383f9be2ca94902e45c756a9979d") + } end it "lets you override the groupingHash" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - event = get_event_from_payload(payload) - expect(event[:groupingHash]).to eq("this is my grouping hash") - end Bugsnag.notify(BugsnagTestException.new("It crashed"), {:grouping_hash => "this is my grouping hash"}) + + expect(Bugsnag).to have_sent_notification{ |payload| + event = get_event_from_payload(payload) + expect(event["groupingHash"]).to eq("this is my grouping hash") + } end it "uses the env variable apiKey" do ENV["BUGSNAG_API_KEY"] = "c9d60ae4c7e70c4b6c4ebd3e8056d2b9" Bugsnag.instance_variable_set(:@configuration, Bugsnag::Configuration.new) Bugsnag.configure do |config| config.release_stage = "production" + config.delivery_method = :synchronous end - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - expect(payload[:apiKey]).to eq("c9d60ae4c7e70c4b6c4ebd3e8056d2b9") - end - Bugsnag.notify(BugsnagTestException.new("It crashed")) + + expect(Bugsnag).to have_sent_notification{ |payload| + expect(payload["apiKey"]).to eq("c9d60ae4c7e70c4b6c4ebd3e8056d2b9") + } end it "has the right exception class" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - exception = get_exception_from_payload(payload) - expect(exception[:errorClass]).to eq("BugsnagTestException") - end - Bugsnag.notify(BugsnagTestException.new("It crashed")) - end - it "has the right exception message" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| exception = get_exception_from_payload(payload) - expect(exception[:message]).to eq("It crashed") - end + expect(exception["errorClass"]).to eq("BugsnagTestException") + } + end + it "has the right exception message" do Bugsnag.notify(BugsnagTestException.new("It crashed")) - end - it "has a valid stacktrace" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| exception = get_exception_from_payload(payload) - expect(exception[:stacktrace].length).to be > 0 - end + expect(exception["message"]).to eq("It crashed") + } + end + it "has a valid stacktrace" do Bugsnag.notify(BugsnagTestException.new("It crashed")) + + expect(Bugsnag).to have_sent_notification{ |payload| + exception = get_exception_from_payload(payload) + expect(exception["stacktrace"].length).to be > 0 + } end # TODO: nested context it "accepts tabs in overrides and adds them to metaData" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - 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 - Bugsnag.notify(BugsnagTestException.new("It crashed"), { :some_tab => { :info => "here", :data => "also here" } }) - end - it "accepts non-hash overrides and adds them to the custom tab in metaData" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| 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 + expect(event["metaData"]["some_tab"]).to eq( + "info" => "here", + "data" => "also here" + ) + } + end + it "accepts non-hash overrides and adds them to the custom tab in metaData" do Bugsnag.notify(BugsnagTestException.new("It crashed"), { :info => "here", :data => "also here" }) - end - it "accepts meta data from an exception that mixes in Bugsnag::MetaData" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| 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 + expect(event["metaData"]["custom"]).to eq( + "info" => "here", + "data" => "also here" + ) + } + end + it "accepts meta data from an exception that mixes in Bugsnag::MetaData" do exception = BugsnagTestExceptionWithMetaData.new("It crashed") exception.bugsnag_meta_data = { :some_tab => { :info => "here", :data => "also here" } } Bugsnag.notify(exception) - end - it "accepts meta data from an exception that mixes in Bugsnag::MetaData, but override using the overrides" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| event = get_event_from_payload(payload) - expect(event[:metaData][:some_tab]).not_to be_nil - expect(event[:metaData][:some_tab][:info]).to eq("overridden") - expect(event[:metaData][:some_tab][:data]).to eq("also here") - end + expect(event["metaData"]["some_tab"]).to eq( + "info" => "here", + "data" => "also here" + ) + } + end + it "accepts meta data from an exception that mixes in Bugsnag::MetaData, but override using the overrides" do exception = BugsnagTestExceptionWithMetaData.new("It crashed") exception.bugsnag_meta_data = { :some_tab => { :info => "here", :data => "also here" } } Bugsnag.notify(exception, {:some_tab => {:info => "overridden"}}) - end - it "accepts user_id from an exception that mixes in Bugsnag::MetaData" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| event = get_event_from_payload(payload) - expect(event[:user][:id]).to eq("exception_user_id") - end + expect(event["metaData"]["some_tab"]).to eq( + "info" => "overridden", + "data" => "also here" + ) + } + end + it "accepts user_id from an exception that mixes in Bugsnag::MetaData" do exception = BugsnagTestExceptionWithMetaData.new("It crashed") exception.bugsnag_user_id = "exception_user_id" Bugsnag.notify(exception) - end - it "accepts user_id from an exception that mixes in Bugsnag::MetaData, but override using the overrides" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| event = get_event_from_payload(payload) - expect(event[:user][:id]).to eq("override_user_id") - end + expect(event["user"]["id"]).to eq("exception_user_id") + } + end + it "accepts user_id from an exception that mixes in Bugsnag::MetaData, but override using the overrides" do exception = BugsnagTestExceptionWithMetaData.new("It crashed") exception.bugsnag_user_id = "exception_user_id" Bugsnag.notify(exception, {:user_id => "override_user_id"}) - end - it "accepts context from an exception that mixes in Bugsnag::MetaData" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| event = get_event_from_payload(payload) - expect(event[:context]).to eq("exception_context") - end + expect(event["user"]["id"]).to eq("override_user_id") + } + end + it "accepts context from an exception that mixes in Bugsnag::MetaData" do exception = BugsnagTestExceptionWithMetaData.new("It crashed") exception.bugsnag_context = "exception_context" Bugsnag.notify(exception) + + expect(Bugsnag).to have_sent_notification{ |payload| + event = get_event_from_payload(payload) + expect(event["context"]).to eq("exception_context") + } end it "accept contexts from an exception that mixes in Bugsnag::MetaData, but override using the overrides" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - event = get_event_from_payload(payload) - expect(event[:context]).to eq("override_context") - end exception = BugsnagTestExceptionWithMetaData.new("It crashed") exception.bugsnag_context = "exception_context" Bugsnag.notify(exception, {:context => "override_context"}) - end - it "accepts meta_data in overrides (for backwards compatibility) and merge it into metaData" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| 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 + expect(event["context"]).to eq("override_context") + } + end + it "accepts meta_data in overrides (for backwards compatibility) and merge it into metaData" do Bugsnag.notify(BugsnagTestException.new("It crashed"), { :meta_data => { :some_tab => { :info => "here", :data => "also here" } } }) + + expect(Bugsnag).to have_sent_notification{ |payload| + event = get_event_from_payload(payload) + expect(event["metaData"]["some_tab"]).to eq( + "info" => "here", + "data" => "also here" + ) + } end it "truncates large meta_data before sending" do - expect(Bugsnag::Notification).to receive(:do_post) do |endpoint, payload_string| - # Truncated body should be no bigger than - # 2 truncated hashes (4096*2) + rest of payload (5000) - expect(payload_string.length).to be < 4096*2 + 5000 - end - Bugsnag.notify(BugsnagTestException.new("It crashed"), { :meta_data => { :some_tab => { :giant => SecureRandom.hex(500_000/2), :mega => SecureRandom.hex(500_000/2) } } }) + + expect(Bugsnag).to have_sent_notification{ |payload| + # Truncated body should be no bigger than + # 2 truncated hashes (4096*2) + rest of payload (5000) + expect(Bugsnag::Helpers.dump_json(payload).length).to be < 4096*2 + 10000 + } end it "accepts a severity in overrides" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - event = get_event_from_payload(payload) - expect(event[:severity]).to eq("info") - end - Bugsnag.notify(BugsnagTestException.new("It crashed"), { :severity => "info" }) - end - it "defaults to warning severity" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| event = get_event_from_payload(payload) - expect(event[:severity]).to eq("warning") - end + expect(event["severity"]).to eq("info") + } - Bugsnag.notify(BugsnagTestException.new("It crashed")) end - it "does not accept a bad severity in overrides" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + it "defaults to warning severity" do + Bugsnag.notify(BugsnagTestException.new("It crashed")) + + expect(Bugsnag).to have_sent_notification{ |payload| event = get_event_from_payload(payload) - expect(event[:severity]).to eq("warning") - end + expect(event["severity"]).to eq("warning") + } + end + it "does not accept a bad severity in overrides" do Bugsnag.notify(BugsnagTestException.new("It crashed"), { :severity => "fatal" }) - end - it "autonotifies errors" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| event = get_event_from_payload(payload) - expect(event[:severity]).to eq("error") - end + expect(event["severity"]).to eq("warning") + } + end + it "autonotifies errors" do Bugsnag.auto_notify(BugsnagTestException.new("It crashed")) + + expect(Bugsnag).to have_sent_notification{ |payload| + event = get_event_from_payload(payload) + expect(event["severity"]).to eq("error") + } end it "accepts a context in overrides" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - event = get_event_from_payload(payload) - expect(event[:context]).to eq("test_context") - end - Bugsnag.notify(BugsnagTestException.new("It crashed"), { :context => "test_context" }) - end - it "accepts a user_id in overrides" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| event = get_event_from_payload(payload) - expect(event[:user][:id]).to eq("test_user") - end + expect(event["context"]).to eq("test_context") + } + end + it "accepts a user_id in overrides" do Bugsnag.notify(BugsnagTestException.new("It crashed"), { :user_id => "test_user" }) + + expect(Bugsnag).to have_sent_notification{ |payload| + event = get_event_from_payload(payload) + expect(event["user"]["id"]).to eq("test_user") + } end it "does not send a notification if auto_notify is false" do Bugsnag.configure do |config| config.auto_notify = false end - expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload) - Bugsnag.auto_notify(BugsnagTestException.new("It crashed")) + + expect(Bugsnag).not_to have_sent_notification end it "contains a release_stage" do Bugsnag.configure do |config| config.release_stage = "production" end - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - event = get_event_from_payload(payload) - expect(event[:app][:releaseStage]).to eq("production") - end - Bugsnag.auto_notify(BugsnagTestException.new("It crashed")) + + expect(Bugsnag).to have_sent_notification{ |payload| + event = get_event_from_payload(payload) + expect(event["app"]["releaseStage"]).to eq("production") + } end it "respects the notify_release_stages setting by not sending in development" do - expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload) - Bugsnag.configuration.notify_release_stages = ["production"] Bugsnag.configuration.release_stage = "development" Bugsnag.notify(BugsnagTestException.new("It crashed")) + + expect(Bugsnag).not_to have_sent_notification end it "respects the notify_release_stages setting when set" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - exception = get_exception_from_payload(payload) - end - Bugsnag.configuration.release_stage = "development" Bugsnag.configuration.notify_release_stages = ["development"] Bugsnag.notify(BugsnagTestException.new("It crashed")) + + expect(Bugsnag).to have_sent_notification{ |payload| + event = get_event_from_payload(payload) + expect(event["exceptions"].length).to eq(1) + } end it "uses the https://notify.bugsnag.com endpoint by default" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - expect(endpoint).to eq("https://notify.bugsnag.com") - end - Bugsnag.notify(BugsnagTestException.new("It crashed")) + + expect(WebMock).to have_requested(:post, "https://notify.bugsnag.com") end it "uses ssl when use_ssl is true" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - expect(endpoint).to start_with "https://" - end - Bugsnag.configuration.use_ssl = true Bugsnag.notify(BugsnagTestException.new("It crashed")) + + expect(WebMock).to have_requested(:post, "https://notify.bugsnag.com") end it "does not use ssl when use_ssl is false" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - expect(endpoint).to start_with "http://" - end - + stub_request(:post, "http://notify.bugsnag.com/") Bugsnag.configuration.use_ssl = false Bugsnag.notify(BugsnagTestException.new("It crashed")) + + expect(WebMock).to have_requested(:post, "http://notify.bugsnag.com") end it "uses ssl when use_ssl is unset" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - expect(endpoint).to start_with "https://" - end - Bugsnag.notify(BugsnagTestException.new("It crashed")) + + expect(WebMock).to have_requested(:post, "https://notify.bugsnag.com") end it "does not mark the top-most stacktrace line as inProject if out of project" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - exception = get_exception_from_payload(payload) - expect(exception[:stacktrace].size).to be >= 1 - expect(exception[:stacktrace].first[:inProject]).to be_nil - end - Bugsnag.configuration.project_root = "/Random/location/here" Bugsnag.notify(BugsnagTestException.new("It crashed")) - end - it "marks the top-most stacktrace line as inProject if necessary" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| exception = get_exception_from_payload(payload) - expect(exception[:stacktrace].size).to be >= 1 - expect(exception[:stacktrace].first[:inProject]).to eq(true) - end + expect(exception["stacktrace"].size).to be >= 1 + expect(exception["stacktrace"].first["inProject"]).to be_nil + } + end + it "marks the top-most stacktrace line as inProject if necessary" do Bugsnag.configuration.project_root = File.expand_path File.dirname(__FILE__) Bugsnag.notify(BugsnagTestException.new("It crashed")) + + expect(Bugsnag).to have_sent_notification{ |payload| + exception = get_exception_from_payload(payload) + expect(exception["stacktrace"].size).to be >= 1 + expect(exception["stacktrace"].first["inProject"]).to eq(true) + } end it "adds app_version to the payload if it is set" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - event = get_event_from_payload(payload) - expect(event[:app][:version]).to eq("1.1.1") - end - Bugsnag.configuration.app_version = "1.1.1" Bugsnag.notify(BugsnagTestException.new("It crashed")) + + expect(Bugsnag).to have_sent_notification{ |payload| + event = get_event_from_payload(payload) + expect(event["app"]["version"]).to eq("1.1.1") + } end it "filters params from all payload hashes if they are set in default params_filters" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - event = get_event_from_payload(payload) - expect(event[:metaData]).not_to be_nil - expect(event[:metaData][:request]).not_to be_nil - expect(event[:metaData][:request][:params]).not_to be_nil - expect(event[:metaData][:request][:params][:password]).to eq("[FILTERED]") - expect(event[:metaData][:request][:params][:other_password]).to eq("[FILTERED]") - expect(event[:metaData][:request][:params][:other_data]).to eq("123456") - end Bugsnag.notify(BugsnagTestException.new("It crashed"), {:request => {:params => {:password => "1234", :other_password => "12345", :other_data => "123456"}}}) + + expect(Bugsnag).to have_sent_notification{ |payload| + event = get_event_from_payload(payload) + expect(event["metaData"]).not_to be_nil + expect(event["metaData"]["request"]).not_to be_nil + expect(event["metaData"]["request"]["params"]).not_to be_nil + expect(event["metaData"]["request"]["params"]["password"]).to eq("[FILTERED]") + expect(event["metaData"]["request"]["params"]["other_password"]).to eq("[FILTERED]") + expect(event["metaData"]["request"]["params"]["other_data"]).to eq("123456") + } end it "filters params from all payload hashes if they are added to params_filters" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - event = get_event_from_payload(payload) - expect(event[:metaData]).not_to be_nil - expect(event[:metaData][:request]).not_to be_nil - expect(event[:metaData][:request][:params]).not_to be_nil - expect(event[:metaData][:request][:params][:password]).to eq("[FILTERED]") - expect(event[:metaData][:request][:params][:other_password]).to eq("[FILTERED]") - expect(event[:metaData][:request][:params][:other_data]).to eq("[FILTERED]") - end Bugsnag.configuration.params_filters << "other_data" Bugsnag.notify(BugsnagTestException.new("It crashed"), {:request => {:params => {:password => "1234", :other_password => "123456", :other_data => "123456"}}}) - end - it "does not filter params from payload hashes if their values are nil" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| event = get_event_from_payload(payload) - expect(event[:metaData]).not_to be_nil - expect(event[:metaData][:request]).not_to be_nil - expect(event[:metaData][:request][:params]).not_to be_nil - expect(event[:metaData][:request][:params]).to have_key(:nil_param) - end + expect(event["metaData"]).not_to be_nil + expect(event["metaData"]["request"]).not_to be_nil + expect(event["metaData"]["request"]["params"]).not_to be_nil + expect(event["metaData"]["request"]["params"]["password"]).to eq("[FILTERED]") + expect(event["metaData"]["request"]["params"]["other_password"]).to eq("[FILTERED]") + expect(event["metaData"]["request"]["params"]["other_data"]).to eq("[FILTERED]") + } + end + it "does not filter params from payload hashes if their values are nil" do Bugsnag.notify(BugsnagTestException.new("It crashed"), {:request => {:params => {:nil_param => nil}}}) + + expect(Bugsnag).to have_sent_notification{ |payload| + event = get_event_from_payload(payload) + expect(event["metaData"]).not_to be_nil + expect(event["metaData"]["request"]).not_to be_nil + expect(event["metaData"]["request"]["params"]).not_to be_nil + expect(event["metaData"]["request"]["params"]).to have_key("nil_param") + } end it "does not notify if the exception class is in the default ignore_classes list" do - expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload) - Bugsnag.notify_or_ignore(ActiveRecord::RecordNotFound.new("It crashed")) + + expect(Bugsnag).not_to have_sent_notification end it "does not notify if the non-default exception class is added to the ignore_classes" do Bugsnag.configuration.ignore_classes << "BugsnagTestException" - expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload) - Bugsnag.notify_or_ignore(BugsnagTestException.new("It crashed")) + + expect(Bugsnag).not_to have_sent_notification end it "does not notify if exception's ancestor is an ignored class" do Bugsnag.configuration.ignore_classes << "BugsnagTestException" - expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload) - Bugsnag.notify_or_ignore(BugsnagSubclassTestException.new("It crashed")) + + expect(Bugsnag).not_to have_sent_notification end it "does not notify if any caused exception is an ignored class" do Bugsnag.configuration.ignore_classes << "NestedException" ex = NestedException.new("Self-referential exception") ex.original_exception = BugsnagTestException.new("It crashed") - expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload) - Bugsnag.notify_or_ignore(ex) + + expect(Bugsnag).not_to have_sent_notification end it "accepts both String and Class instances as an ignored class" do Bugsnag.configuration.ignore_classes << BugsnagTestException - expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload) - Bugsnag.notify_or_ignore(BugsnagTestException.new("It crashed")) + + expect(Bugsnag).not_to have_sent_notification end it "does not notify if the user agent is present and matches a regex in ignore_user_agents" do Bugsnag.configuration.ignore_user_agents << %r{BugsnagUserAgent} - expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload) - ((Thread.current["bugsnag_req_data"] ||= {})[:rack_env] ||= {})["HTTP_USER_AGENT"] = "BugsnagUserAgent" Bugsnag.notify_or_ignore(BugsnagTestException.new("It crashed")) + + expect(Bugsnag::Notification).not_to have_sent_notification end it "sends the cause of the exception" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - event = get_event_from_payload(payload) - expect(event[:exceptions].size).to eq(2) - end - begin begin raise "jiminey" rescue Ruby21Exception.raise! "cricket" end rescue Bugsnag.notify $! end - end - it "does not unwrap the same exception twice" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| event = get_event_from_payload(payload) - expect(event[:exceptions].size).to eq(1) - end + expect(event["exceptions"].size).to eq(2) + } + end + it "does not unwrap the same exception twice" do ex = NestedException.new("Self-referential exception") ex.original_exception = ex Bugsnag.notify_or_ignore(ex) + + expect(Bugsnag).to have_sent_notification{ |payload| + event = get_event_from_payload(payload) + expect(event["exceptions"].size).to eq(1) + } end it "does not unwrap more than 5 exceptions" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - event = get_event_from_payload(payload) - expect(event[:exceptions].size).to eq(5) - end first_ex = ex = NestedException.new("Deep exception") 10.times do |idx| ex = ex.original_exception = NestedException.new("Deep exception #{idx}") end Bugsnag.notify_or_ignore(first_ex) + expect(Bugsnag).to have_sent_notification{ |payload| + event = get_event_from_payload(payload) + expect(event["exceptions"].size).to eq(5) + } end it "calls to_exception on i18n error objects" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - exception = get_exception_from_payload(payload) - expect(exception[:errorClass]).to eq("BugsnagTestException") - expect(exception[:message]).to eq("message") - end - Bugsnag.notify(OpenStruct.new(:to_exception => BugsnagTestException.new("message"))) - end - it "generates runtimeerror for non exceptions" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + expect(Bugsnag).to have_sent_notification{ |payload| exception = get_exception_from_payload(payload) - expect(exception[:errorClass]).to eq("RuntimeError") - expect(exception[:message]).to eq("test message") - end + expect(exception["errorClass"]).to eq("BugsnagTestException") + expect(exception["message"]).to eq("message") + } + end + it "generates runtimeerror for non exceptions" do notify_test_exception + + expect(Bugsnag).to have_sent_notification{ |payload| + exception = get_exception_from_payload(payload) + expect(exception["errorClass"]).to eq("RuntimeError") + expect(exception["message"]).to eq("test message") + } end it "supports unix-style paths in backtraces" do ex = BugsnagTestException.new("It crashed") ex.set_backtrace([ "/Users/james/app/spec/notification_spec.rb:419", "/Some/path/rspec/example.rb:113:in `instance_eval'" ]) - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + Bugsnag.notify(ex) + + expect(Bugsnag).to have_sent_notification{ |payload| exception = get_exception_from_payload(payload) - expect(exception[:stacktrace].length).to eq(2) + expect(exception["stacktrace"].length).to eq(2) - line = exception[:stacktrace][0] - expect(line[:file]).to eq("/Users/james/app/spec/notification_spec.rb") - expect(line[:lineNumber]).to eq(419) - expect(line[:method]).to be nil + line = exception["stacktrace"][0] + expect(line["file"]).to eq("/Users/james/app/spec/notification_spec.rb") + expect(line["lineNumber"]).to eq(419) + expect(line["method"]).to be nil - line = exception[:stacktrace][1] - expect(line[:file]).to eq("/Some/path/rspec/example.rb") - expect(line[:lineNumber]).to eq(113) - expect(line[:method]).to eq("instance_eval") - end - - Bugsnag.notify(ex) + line = exception["stacktrace"][1] + expect(line["file"]).to eq("/Some/path/rspec/example.rb") + expect(line["lineNumber"]).to eq(113) + expect(line["method"]).to eq("instance_eval") + } end it "supports windows-style paths in backtraces" do ex = BugsnagTestException.new("It crashed") ex.set_backtrace([ "C:/projects/test/app/controllers/users_controller.rb:13:in `index'", "C:/ruby/1.9.1/gems/actionpack-2.3.10/filters.rb:638:in `block in run_before_filters'" ]) - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| + Bugsnag.notify(ex) + + expect(Bugsnag).to have_sent_notification{ |payload| exception = get_exception_from_payload(payload) - expect(exception[:stacktrace].length).to eq(2) + expect(exception["stacktrace"].length).to eq(2) - line = exception[:stacktrace][0] - expect(line[:file]).to eq("C:/projects/test/app/controllers/users_controller.rb") - expect(line[:lineNumber]).to eq(13) - expect(line[:method]).to eq("index") + line = exception["stacktrace"][0] + expect(line["file"]).to eq("C:/projects/test/app/controllers/users_controller.rb") + expect(line["lineNumber"]).to eq(13) + expect(line["method"]).to eq("index") - line = exception[:stacktrace][1] - expect(line[:file]).to eq("C:/ruby/1.9.1/gems/actionpack-2.3.10/filters.rb") - expect(line[:lineNumber]).to eq(638) - expect(line[:method]).to eq("block in run_before_filters") - end - - Bugsnag.notify(ex) + line = exception["stacktrace"][1] + expect(line["file"]).to eq("C:/ruby/1.9.1/gems/actionpack-2.3.10/filters.rb") + expect(line["lineNumber"]).to eq(638) + expect(line["method"]).to eq("block in run_before_filters") + } end it "uses a proxy host if configured" do Bugsnag.configure do |config| config.proxy_host = "host_name" @@ -711,29 +712,34 @@ it "should fix invalid utf8" do invalid_data = "fl\xc3ff" invalid_data.force_encoding('BINARY') if invalid_data.respond_to?(:force_encoding) - expect(Bugsnag::Notification).to receive(:do_post) do |endpoint, payload_string| - expect(payload_string).to match(/fl�ff/) if defined?(Encoding::UTF_8) - end - notify_test_exception(:fluff => {:fluff => invalid_data}) + + expect(Bugsnag).to have_sent_notification{ |payload| + if defined?(Encoding::UTF_8) + expect(payload.to_json).to match(/fl�ff/) + else + expect(payload.to_json).to match(/flff/) + end + } end if defined?(JRUBY_VERSION) it "should work with java.lang.Throwables" do - expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload| - expect(payload[:events][0][:exceptions][0][:errorClass]).to eq('Java::JavaLang::ArrayIndexOutOfBoundsException') - expect(payload[:events][0][:exceptions][0][:message]).to eq("2") - expect(payload[:events][0][:exceptions][0][:stacktrace].size).to be > 0 - end - begin JRubyException.raise! rescue Bugsnag.notify $! end + + expect(Bugsnag).to have_sent_notification{ |payload| + exception = get_exception_from_payload(payload) + expect(exception["errorClass"]).to eq('Java::JavaLang::ArrayIndexOutOfBoundsException') + expect(exception["message"]).to eq("2") + expect(exception["stacktrace"].size).to be > 0 + } end end end