From 1360276e2e01d973ac0a33b9b91bf4f4abfc3d88 Mon Sep 17 00:00:00 2001 From: Alex Moinet Date: Fri, 16 Nov 2018 17:20:09 +0000 Subject: [PATCH 01/13] Bugsnag frames InProject: Remove nilification of Bugsnag lib frames --- lib/bugsnag/stacktrace.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bugsnag/stacktrace.rb b/lib/bugsnag/stacktrace.rb index b3b257815..1075296f5 100644 --- a/lib/bugsnag/stacktrace.rb +++ b/lib/bugsnag/stacktrace.rb @@ -27,7 +27,7 @@ def initialize(backtrace, configuration) # Parse the stacktrace line # Skip stacktrace lines inside lib/bugsnag - next(nil) if file.nil? || file =~ %r{lib/bugsnag(/|\.rb)} + next(nil) if file.nil? # Expand relative paths p = Pathname.new(file) From 60a87294e5336f1dd7dcbd3555bbb8f79b22aec9 Mon Sep 17 00:00:00 2001 From: Alex Moinet Date: Fri, 16 Nov 2018 17:28:25 +0000 Subject: [PATCH 02/13] Bugsnag frames InProject: Update report spec frames --- spec/report_spec.rb | 15 ++++++++------- spec/spec_helper.rb | 6 ++++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/spec/report_spec.rb b/spec/report_spec.rb index 2dfe43ad5..4631e66f3 100644 --- a/spec/report_spec.rb +++ b/spec/report_spec.rb @@ -501,7 +501,7 @@ def gloops 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 + it "does not mark the top-most non-bugsnag stacktrace line as inProject if out of project" do Bugsnag.configuration.project_root = "/Random/location/here" Bugsnag.notify(BugsnagTestException.new("It crashed")) @@ -512,14 +512,15 @@ def gloops } end - it "marks the top-most stacktrace line as inProject if necessary" do + it "marks the top-most non-bugsnag 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, headers| exception = get_exception_from_payload(payload) expect(exception["stacktrace"].size).to be >= 1 - expect(exception["stacktrace"].first["inProject"]).to eq(true) + top_frame = get_top_project_frame(exception["stacktrace"]) + expect(top_frame["inProject"]).to eq(true) } end @@ -1051,11 +1052,11 @@ def gloops expect(exception["errorClass"]).to eq("RuntimeError") expect(exception["message"]).to eq("'nil' was notified as an exception") - stacktrace = exception["stacktrace"][0] - expect(stacktrace["lineNumber"]).to eq(1047) + stacktrace = get_top_project_frame(exception["stacktrace"]) + expect(stacktrace["lineNumber"]).to eq(1048) expect(stacktrace["file"]).to end_with("spec/report_spec.rb") - expect(stacktrace["code"]["1046"]).to eq(" it 'uses an appropriate message if nil is notified' do") - expect(stacktrace["code"]["1047"]).to eq(" Bugsnag.notify(nil)") + expect(stacktrace["code"]["1047"]).to eq(" it 'uses an appropriate message if nil is notified' do") + expect(stacktrace["code"]["1048"]).to eq(" Bugsnag.notify(nil)") } end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2f6061dab..5900fb056 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -84,3 +84,9 @@ def have_sent_notification(&matcher) end end end + +def get_top_project_frame(stacktrace) + stacktrace.find do |frame| + frame !=~ %r{lib/bugsnag(/|\.rb)} + end +end \ No newline at end of file From 179f3bee59f179b2717ad19b88c1c77d3c3fe37b Mon Sep 17 00:00:00 2001 From: Alex Moinet Date: Mon, 19 Nov 2018 13:58:41 +0000 Subject: [PATCH 03/13] Bugsnag frames InProject: Ensure correct frame is passed back --- spec/spec_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 5900fb056..1acff712e 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -87,6 +87,6 @@ def have_sent_notification(&matcher) def get_top_project_frame(stacktrace) stacktrace.find do |frame| - frame !=~ %r{lib/bugsnag(/|\.rb)} + /.*lib\/bugsnag.*\.rb/.match(frame["file"]).nil? end end \ No newline at end of file From a99e452550a690bf119518ae6bb06efdb1f0fac5 Mon Sep 17 00:00:00 2001 From: Alex Moinet Date: Mon, 19 Nov 2018 14:08:26 +0000 Subject: [PATCH 04/13] Bugsnag frame InProject: Allow non-top frame to be selected --- spec/report_spec.rb | 4 ++-- spec/spec_helper.rb | 13 +++++++++++-- spec/stacktrace_spec.rb | 5 +++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/spec/report_spec.rb b/spec/report_spec.rb index 4631e66f3..f41d0bc7d 100644 --- a/spec/report_spec.rb +++ b/spec/report_spec.rb @@ -519,7 +519,7 @@ def gloops expect(Bugsnag).to have_sent_notification{ |payload, headers| exception = get_exception_from_payload(payload) expect(exception["stacktrace"].size).to be >= 1 - top_frame = get_top_project_frame(exception["stacktrace"]) + top_frame = get_project_frame(exception["stacktrace"]) expect(top_frame["inProject"]).to eq(true) } end @@ -1052,7 +1052,7 @@ def gloops expect(exception["errorClass"]).to eq("RuntimeError") expect(exception["message"]).to eq("'nil' was notified as an exception") - stacktrace = get_top_project_frame(exception["stacktrace"]) + stacktrace = get_project_frame(exception["stacktrace"]) expect(stacktrace["lineNumber"]).to eq(1048) expect(stacktrace["file"]).to end_with("spec/report_spec.rb") expect(stacktrace["code"]["1047"]).to eq(" it 'uses an appropriate message if nil is notified' do") diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1acff712e..29dea9448 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -85,8 +85,17 @@ def have_sent_notification(&matcher) end end -def get_top_project_frame(stacktrace) +def get_project_frame(stacktrace, count=0) + index = 0 stacktrace.find do |frame| - /.*lib\/bugsnag.*\.rb/.match(frame["file"]).nil? + found = false + if /.*lib\/bugsnag.*\.rb/.match(frame["file"]).nil? + if index == count + found = true + else + index += 1 + found = false + end + end end end \ No newline at end of file diff --git a/spec/stacktrace_spec.rb b/spec/stacktrace_spec.rb index 749477fbd..cd7f2072d 100644 --- a/spec/stacktrace_spec.rb +++ b/spec/stacktrace_spec.rb @@ -12,8 +12,9 @@ expect(Bugsnag).to have_sent_notification{ |payload, headers| exception = get_exception_from_payload(payload) - starting_line = __LINE__ - 10 - expect(exception["stacktrace"][1]["code"]).to eq({ + starting_frame = get_project_frame(exception["stacktrace"], 1) + starting_line = __LINE__ - 11 + expect(starting_frame["code"]).to eq({ (starting_line + 0).to_s => " _a = 1", (starting_line + 1).to_s => " _b = 2", (starting_line + 2).to_s => " _c = 3", From 02bf1c95aeee8490ac4be659ae789d0c662a92da Mon Sep 17 00:00:00 2001 From: Alex Moinet Date: Mon, 19 Nov 2018 14:41:02 +0000 Subject: [PATCH 05/13] Bugsnag frames InProject: Add Bugsnag frames tests --- spec/stacktrace_spec.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/spec/stacktrace_spec.rb b/spec/stacktrace_spec.rb index cd7f2072d..c958c6592 100644 --- a/spec/stacktrace_spec.rb +++ b/spec/stacktrace_spec.rb @@ -26,6 +26,21 @@ } end + it "includes bugsnag lines marked out of project" do + notify_test_exception + expect(Bugsnag).to have_sent_notification{ |payload, headers| + exception = get_exception_from_payload(payload) + bugsnag_count = 0 + exception["stacktrace"].each do |frame| + if /.*lib\/bugsnag.*\.rb/.match(frame["file"]) + bugsnag_count += 1 + expect(frame["inProject"]).to be_nil + end + end + expect(bugsnag_count).to be > 0 + } + end + it "allows you to disable sending code" do Bugsnag.configuration.send_code = false From eb8ae6268c606fd5fd71e73ec6d650d90bbfb6a8 Mon Sep 17 00:00:00 2001 From: Alex Moinet Date: Tue, 20 Nov 2018 13:44:04 +0000 Subject: [PATCH 06/13] Bugsnag frames InProject: Cleared up comments and tests --- lib/bugsnag/stacktrace.rb | 1 - spec/report_spec.rb | 40 +++++++++++++++++++++--------- spec/spec_helper.rb | 15 ----------- spec/stacktrace_spec.rb | 52 +++++++++++++++------------------------ 4 files changed, 49 insertions(+), 59 deletions(-) diff --git a/lib/bugsnag/stacktrace.rb b/lib/bugsnag/stacktrace.rb index 1075296f5..42a82461d 100644 --- a/lib/bugsnag/stacktrace.rb +++ b/lib/bugsnag/stacktrace.rb @@ -26,7 +26,6 @@ def initialize(backtrace, configuration) # Parse the stacktrace line - # Skip stacktrace lines inside lib/bugsnag next(nil) if file.nil? # Expand relative paths diff --git a/spec/report_spec.rb b/spec/report_spec.rb index f41d0bc7d..944d75228 100644 --- a/spec/report_spec.rb +++ b/spec/report_spec.rb @@ -501,9 +501,14 @@ def gloops expect(WebMock).to have_requested(:post, "https://notify.bugsnag.com") end - it "does not mark the top-most non-bugsnag stacktrace line as inProject if out of project" do + it "does not mark the top-most stacktrace line as inProject if out of project" do Bugsnag.configuration.project_root = "/Random/location/here" - Bugsnag.notify(BugsnagTestException.new("It crashed")) + + begin + "Test".prepnd "T" + rescue Exception => e + Bugsnag.notify(e) + end expect(Bugsnag).to have_sent_notification{ |payload, headers| exception = get_exception_from_payload(payload) @@ -512,15 +517,19 @@ def gloops } end - it "marks the top-most non-bugsnag stacktrace line as inProject if necessary" do + 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")) + + begin + "Test".prepnd "T" + rescue Exception => e + Bugsnag.notify(e) + end expect(Bugsnag).to have_sent_notification{ |payload, headers| exception = get_exception_from_payload(payload) expect(exception["stacktrace"].size).to be >= 1 - top_frame = get_project_frame(exception["stacktrace"]) - expect(top_frame["inProject"]).to eq(true) + expect(exception["stacktrace"][0]["inProject"]).to eq(true) } end @@ -1051,12 +1060,21 @@ def gloops exception = event["exceptions"][0] expect(exception["errorClass"]).to eq("RuntimeError") expect(exception["message"]).to eq("'nil' was notified as an exception") + } + end - stacktrace = get_project_frame(exception["stacktrace"]) - expect(stacktrace["lineNumber"]).to eq(1048) - expect(stacktrace["file"]).to end_with("spec/report_spec.rb") - expect(stacktrace["code"]["1047"]).to eq(" it 'uses an appropriate message if nil is notified' do") - expect(stacktrace["code"]["1048"]).to eq(" Bugsnag.notify(nil)") + it "includes bugsnag lines marked out of project" do + notify_test_exception + expect(Bugsnag).to have_sent_notification{ |payload, headers| + exception = get_exception_from_payload(payload) + bugsnag_count = 0 + exception["stacktrace"].each do |frame| + if /.*lib\/bugsnag.*\.rb/.match(frame["file"]) + bugsnag_count += 1 + expect(frame["inProject"]).to be_nil + end + end + expect(bugsnag_count).to be > 0 } end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 29dea9448..6584fd1ea 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -83,19 +83,4 @@ def have_sent_notification(&matcher) raise "no matcher provided to have_sent_notification (did you use { })" end end -end - -def get_project_frame(stacktrace, count=0) - index = 0 - stacktrace.find do |frame| - found = false - if /.*lib\/bugsnag.*\.rb/.match(frame["file"]).nil? - if index == count - found = true - else - index += 1 - found = false - end - end - end end \ No newline at end of file diff --git a/spec/stacktrace_spec.rb b/spec/stacktrace_spec.rb index c958c6592..44caf934c 100644 --- a/spec/stacktrace_spec.rb +++ b/spec/stacktrace_spec.rb @@ -2,45 +2,33 @@ describe Bugsnag::Stacktrace do it "includes code in the stack trace" do - _a = 1 - _b = 2 - _c = 3 - notify_test_exception - _d = 4 - _e = 5 - _f = 6 + begin + _a = 1 + _b = 2 + _c = 3 + "Test".prepnd "T" + _d = 4 + _e = 5 + _f = 6 + rescue Exception => e + Bugsnag.notify(e) + end expect(Bugsnag).to have_sent_notification{ |payload, headers| exception = get_exception_from_payload(payload) - starting_frame = get_project_frame(exception["stacktrace"], 1) - starting_line = __LINE__ - 11 - expect(starting_frame["code"]).to eq({ - (starting_line + 0).to_s => " _a = 1", - (starting_line + 1).to_s => " _b = 2", - (starting_line + 2).to_s => " _c = 3", - (starting_line + 3).to_s => " notify_test_exception", - (starting_line + 4).to_s => " _d = 4", - (starting_line + 5).to_s => " _e = 5", - (starting_line + 6).to_s => " _f = 6" + starting_line = __LINE__ - 13 + expect(exception["stacktrace"][0]["code"]).to eq({ + (starting_line + 0).to_s => " _a = 1", + (starting_line + 1).to_s => " _b = 2", + (starting_line + 2).to_s => " _c = 3", + (starting_line + 3).to_s => " \"Test\".prepnd \"T\"", + (starting_line + 4).to_s => " _d = 4", + (starting_line + 5).to_s => " _e = 5", + (starting_line + 6).to_s => " _f = 6" }) } end - it "includes bugsnag lines marked out of project" do - notify_test_exception - expect(Bugsnag).to have_sent_notification{ |payload, headers| - exception = get_exception_from_payload(payload) - bugsnag_count = 0 - exception["stacktrace"].each do |frame| - if /.*lib\/bugsnag.*\.rb/.match(frame["file"]) - bugsnag_count += 1 - expect(frame["inProject"]).to be_nil - end - end - expect(bugsnag_count).to be > 0 - } - end - it "allows you to disable sending code" do Bugsnag.configuration.send_code = false From 9e14ecf4aa7b4edaa6d5e193154b2276097083ad Mon Sep 17 00:00:00 2001 From: Alex Moinet Date: Fri, 23 Nov 2018 12:37:23 +0000 Subject: [PATCH 07/13] Bugsnag frames inproject: Updated maze tests --- .../plain_features/handled_errors.feature | 8 +++--- .../report_stack_frames.feature | 6 ++--- features/steps/ruby_notifier_steps.rb | 26 +++++++++++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/features/plain_features/handled_errors.feature b/features/plain_features/handled_errors.feature index 0c183206c..d93c51506 100644 --- a/features/plain_features/handled_errors.feature +++ b/features/plain_features/handled_errors.feature @@ -17,8 +17,8 @@ Scenario Outline: A handled error sends a report And the event "severity" equals "warning" And the event "severityReason.type" equals "handledException" And the exception "errorClass" equals "RuntimeError" - And the "file" of stack frame 0 equals "/usr/src/app/handled/.rb" - And the "lineNumber" of stack frame 0 equals + And the "file" of the top project stackframe equals "/usr/src/app/handled/.rb" + And the "lineNumber" of the top project stackframe equals Examples: | ruby version | file | lineNumber | @@ -67,8 +67,8 @@ Scenario Outline: A handled error can attach metadata in a block And the event "severity" equals "warning" And the event "severityReason.type" equals "handledException" And the exception "errorClass" equals "RuntimeError" - And the "file" of stack frame 0 equals "/usr/src/app/handled/block_metadata.rb" - And the "lineNumber" of stack frame 0 equals 6 + And the "file" of the top project stackframe equals "/usr/src/app/handled/block_metadata.rb" + And the "lineNumber" of the top project stackframe equals 6 And the event "metaData.account.id" equals "1234abcd" And the event "metaData.account.name" equals "Acme Co" And the event "metaData.account.support" is true diff --git a/features/plain_features/report_stack_frames.feature b/features/plain_features/report_stack_frames.feature index f37dddd5a..58d89cc2e 100644 --- a/features/plain_features/report_stack_frames.feature +++ b/features/plain_features/report_stack_frames.feature @@ -14,8 +14,8 @@ Scenario Outline: Stack frames can be removed And the request used the "Ruby Bugsnag Notifier" notifier And the request used payload v4 headers And the request contained the api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the "file" of stack frame 0 equals "/usr/src/app/stack_frame_modification/initiators/.rb" - And the "lineNumber" of stack frame 0 equals + And the "file" of the top project stackframe equals "/usr/src/app/stack_frame_modification/initiators/.rb" + And the "lineNumber" of the top project stackframe equals Examples: | ruby version | initiator | lineNumber | @@ -51,7 +51,7 @@ Scenario Outline: Stack frames can be marked as in project And the request used the "Ruby Bugsnag Notifier" notifier And the request used payload v4 headers And the request contained the api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the "file" of stack frame 0 equals "/usr/src/app/stack_frame_modification/initiators/.rb" + And the "file" of the top project stackframe equals "/usr/src/app/stack_frame_modification/initiators/.rb" And the event "exceptions.0.stacktrace.0.inProject" is null And the event "exceptions.0.stacktrace.1.inProject" is true And the event "exceptions.0.stacktrace.2.inProject" is true diff --git a/features/steps/ruby_notifier_steps.rb b/features/steps/ruby_notifier_steps.rb index b14c167a8..cbe9971b5 100644 --- a/features/steps/ruby_notifier_steps.rb +++ b/features/steps/ruby_notifier_steps.rb @@ -12,4 +12,30 @@ steps %Q{ When I set environment variable "#{env_var}" to "#{credentials}@#{current_ip}:#{MOCK_API_PORT}" } +end +Then(/^the "(.+)" of the top project stackframe equals "(.+)"(?: for request (\d+))?$/) do |element, value, request_index| + stacktrace = read_key_path(find_request(request_index)[:body], 'events.0.exceptions.0.stacktrace') + frame_index = 0 + stacktrace.each do |frame, index| + unless /.*lib\/bugsnag.*\.rb/.match(frame["file"]) + frame_index = index + break + end + end + steps %Q{ + the "#{element}" of stack frame #{frame_index} equals "#{value}" + } +end +Then(/^the "(.+)" of the top project stackframe equals (\d+)(?: for request (\d+))?$/) do |element, value, request_index| + stacktrace = read_key_path(find_request(request_index)[:body], 'events.0.exceptions.0.stacktrace') + frame_index = 0 + stacktrace.each do |frame, index| + unless /.*lib\/bugsnag.*\.rb/.match(frame["file"]) + frame_index = index + break + end + end + steps %Q{ + the "#{element}" of stack frame #{frame_index} equals #{value} + } end \ No newline at end of file From 90594cf871f2846a1173c29fb33af561f9a5b378 Mon Sep 17 00:00:00 2001 From: Alex Moinet Date: Mon, 26 Nov 2018 14:27:56 +0000 Subject: [PATCH 08/13] Bugsnag frame inproject: Updates rails tests --- features/rails_features/project_root.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/rails_features/project_root.feature b/features/rails_features/project_root.feature index c98df2696..3804355b2 100644 --- a/features/rails_features/project_root.feature +++ b/features/rails_features/project_root.feature @@ -18,7 +18,7 @@ Scenario Outline: Project_root should default to Rails.root And the exception "errorClass" equals "RuntimeError" And the exception "message" starts with "handled string" And the event "metaData.request.url" ends with "/project_root/default" - And the "file" of stack frame 0 equals "app/controllers/project_root_controller.rb" + And the "file" of the top project stackframe equals "app/controllers/project_root_controller.rb" Examples: | ruby_version | rails_version | @@ -49,7 +49,7 @@ Scenario Outline: Project_root can be set in an initializer And the exception "errorClass" equals "RuntimeError" And the exception "message" starts with "handled string" And the event "metaData.request.url" ends with "/project_root/initializer" - And the "file" of stack frame 0 equals "/usr/src/app/controllers/project_root_controller.rb" + And the "file" of the top project stackframe equals "/usr/src/app/controllers/project_root_controller.rb" Examples: | ruby_version | rails_version | @@ -79,7 +79,7 @@ Scenario Outline: Project_root can be set after an initializer And the exception "errorClass" equals "RuntimeError" And the exception "message" starts with "handled string" And the event "metaData.request.url" ends with "/project_root/after" - And the "file" of stack frame 0 equals "/usr/src/app/controllers/project_root_controller.rb" + And the "file" of the top project stackframe equals "/usr/src/app/controllers/project_root_controller.rb" Examples: | ruby_version | rails_version | From 07ea1bfc17437996f45ad250fa2430cf4bb7ac30 Mon Sep 17 00:00:00 2001 From: Alex Moinet Date: Mon, 26 Nov 2018 16:27:33 +0000 Subject: [PATCH 09/13] Bugsnag frames inproject: Updates to stackframe maze tests --- .../initiators/handled_before_notify.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/features/fixtures/plain/app/stack_frame_modification/initiators/handled_before_notify.rb b/features/fixtures/plain/app/stack_frame_modification/initiators/handled_before_notify.rb index 544c42827..6e54300f9 100644 --- a/features/fixtures/plain/app/stack_frame_modification/initiators/handled_before_notify.rb +++ b/features/fixtures/plain/app/stack_frame_modification/initiators/handled_before_notify.rb @@ -21,5 +21,9 @@ def step_three end def crash - Bugsnag.notify(RuntimeError.new("oh no")) + begin + "Test".insrt(-1, "!") + rescue Exception => e + Bugsnag.notify(e) + end end \ No newline at end of file From 25b5b9467313c7117973d1db2607e10edcf1a473 Mon Sep 17 00:00:00 2001 From: Alex Moinet Date: Wed, 28 Nov 2018 16:38:07 +0000 Subject: [PATCH 10/13] Bugsnag frames in-project: Updated tests to better reflect new stackframe ordering --- .../plain_features/handled_errors.feature | 8 +-- .../report_stack_frames.feature | 71 ++++++++++++++----- features/rails_features/project_root.feature | 6 +- features/steps/ruby_notifier_steps.rb | 26 ++----- spec/report_spec.rb | 10 ++- 5 files changed, 74 insertions(+), 47 deletions(-) diff --git a/features/plain_features/handled_errors.feature b/features/plain_features/handled_errors.feature index d93c51506..b81e83f95 100644 --- a/features/plain_features/handled_errors.feature +++ b/features/plain_features/handled_errors.feature @@ -17,8 +17,8 @@ Scenario Outline: A handled error sends a report And the event "severity" equals "warning" And the event "severityReason.type" equals "handledException" And the exception "errorClass" equals "RuntimeError" - And the "file" of the top project stackframe equals "/usr/src/app/handled/.rb" - And the "lineNumber" of the top project stackframe equals + And the "file" of the top non-bugsnag stackframe equals "/usr/src/app/handled/.rb" + And the "lineNumber" of the top non-bugsnag stackframe equals Examples: | ruby version | file | lineNumber | @@ -67,8 +67,8 @@ Scenario Outline: A handled error can attach metadata in a block And the event "severity" equals "warning" And the event "severityReason.type" equals "handledException" And the exception "errorClass" equals "RuntimeError" - And the "file" of the top project stackframe equals "/usr/src/app/handled/block_metadata.rb" - And the "lineNumber" of the top project stackframe equals 6 + And the "file" of the top non-bugsnag stackframe equals "/usr/src/app/handled/block_metadata.rb" + And the "lineNumber" of the top non-bugsnag stackframe equals 6 And the event "metaData.account.id" equals "1234abcd" And the event "metaData.account.name" equals "Acme Co" And the event "metaData.account.support" is true diff --git a/features/plain_features/report_stack_frames.feature b/features/plain_features/report_stack_frames.feature index 58d89cc2e..c6c6a5652 100644 --- a/features/plain_features/report_stack_frames.feature +++ b/features/plain_features/report_stack_frames.feature @@ -14,33 +14,49 @@ Scenario Outline: Stack frames can be removed And the request used the "Ruby Bugsnag Notifier" notifier And the request used payload v4 headers And the request contained the api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the "file" of the top project stackframe equals "/usr/src/app/stack_frame_modification/initiators/.rb" - And the "lineNumber" of the top project stackframe equals + And the "file" of the top non-bugsnag stackframe equals "/usr/src/app/stack_frame_modification/initiators/.rb" + And the "lineNumber" of stack frame 0 equals Examples: | ruby version | initiator | lineNumber | | 1.9.3 | handled_before_notify | 20 | - | 1.9.3 | handled_block | 19 | | 1.9.3 | unhandled_before_notify | 21 | | 2.0 | handled_before_notify | 20 | - | 2.0 | handled_block | 19 | | 2.0 | unhandled_before_notify | 21 | | 2.1 | handled_before_notify | 20 | - | 2.1 | handled_block | 19 | | 2.1 | unhandled_before_notify | 21 | | 2.2 | handled_before_notify | 20 | - | 2.2 | handled_block | 19 | | 2.2 | unhandled_before_notify | 21 | | 2.3 | handled_before_notify | 20 | - | 2.3 | handled_block | 19 | | 2.3 | unhandled_before_notify | 21 | | 2.4 | handled_before_notify | 20 | - | 2.4 | handled_block | 19 | | 2.4 | unhandled_before_notify | 21 | | 2.5 | handled_before_notify | 20 | - | 2.5 | handled_block | 19 | | 2.5 | unhandled_before_notify | 21 | +Scenario Outline: Stack frames can be removed + Given I set environment variable "RUBY_VERSION" to "" + And I set environment variable "CALLBACK_INITIATOR" to "handled_block" + And I have built the service "plain-ruby" + And I run the service "plain-ruby" with the command "bundle exec ruby stack_frame_modification/remove_stack_frame.rb" + And I wait for 1 second + Then I should receive a request + And the request used the "Ruby Bugsnag Notifier" notifier + And the request used payload v4 headers + And the request contained the api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + And the "file" of the top non-bugsnag stackframe equals "/usr/src/app/stack_frame_modification/initiators/handled_block.rb" + And the "lineNumber" of the top non-bugsnag stackframe equals + + Examples: + | ruby version | lineNumber | + | 1.9.3 | 19 | + | 2.0 | 19 | + | 2.1 | 19 | + | 2.2 | 19 | + | 2.3 | 19 | + | 2.4 | 19 | + | 2.5 | 19 | + Scenario Outline: Stack frames can be marked as in project Given I set environment variable "RUBY_VERSION" to "" And I set environment variable "CALLBACK_INITIATOR" to "" @@ -51,7 +67,7 @@ Scenario Outline: Stack frames can be marked as in project And the request used the "Ruby Bugsnag Notifier" notifier And the request used payload v4 headers And the request contained the api key "a35a2a72bd230ac0aa0f52715bbdc6aa" - And the "file" of the top project stackframe equals "/usr/src/app/stack_frame_modification/initiators/.rb" + And the "file" of stack frame 0 equals "/usr/src/app/stack_frame_modification/initiators/.rb" And the event "exceptions.0.stacktrace.0.inProject" is null And the event "exceptions.0.stacktrace.1.inProject" is true And the event "exceptions.0.stacktrace.2.inProject" is true @@ -60,23 +76,42 @@ Scenario Outline: Stack frames can be marked as in project Examples: | ruby version | initiator | | 1.9.3 | handled_before_notify | - | 1.9.3 | handled_block | | 1.9.3 | unhandled_before_notify | | 2.0 | handled_before_notify | - | 2.0 | handled_block | | 2.0 | unhandled_before_notify | | 2.1 | handled_before_notify | - | 2.1 | handled_block | | 2.1 | unhandled_before_notify | | 2.2 | handled_before_notify | - | 2.2 | handled_block | | 2.2 | unhandled_before_notify | | 2.3 | handled_before_notify | - | 2.3 | handled_block | | 2.3 | unhandled_before_notify | | 2.4 | handled_before_notify | - | 2.4 | handled_block | | 2.4 | unhandled_before_notify | | 2.5 | handled_before_notify | - | 2.5 | handled_block | - | 2.5 | unhandled_before_notify | \ No newline at end of file + | 2.5 | unhandled_before_notify | + +Scenario Outline: Stack frames can be marked as in project with a handled string + Given I set environment variable "RUBY_VERSION" to "" + And I set environment variable "CALLBACK_INITIATOR" to "handled_block" + And I have built the service "plain-ruby" + And I run the service "plain-ruby" with the command "bundle exec ruby stack_frame_modification/mark_frames_in_project.rb" + And I wait for 1 second + Then I should receive a request + And the request used the "Ruby Bugsnag Notifier" notifier + And the request used payload v4 headers + And the request contained the api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + And the "file" of the top non-bugsnag stackframe equals "/usr/src/app/stack_frame_modification/initiators/handled_block.rb" + And the event "exceptions.0.stacktrace.0.inProject" is null + And the event "exceptions.0.stacktrace.1.inProject" is true + And the event "exceptions.0.stacktrace.2.inProject" is true + And the event "exceptions.0.stacktrace.3.inProject" is true + + Examples: + | ruby version | + | 1.9.3 | + | 2.0 | + | 2.1 | + | 2.2 | + | 2.3 | + | 2.4 | + | 2.5 | \ No newline at end of file diff --git a/features/rails_features/project_root.feature b/features/rails_features/project_root.feature index 3804355b2..f906ec5ba 100644 --- a/features/rails_features/project_root.feature +++ b/features/rails_features/project_root.feature @@ -18,7 +18,7 @@ Scenario Outline: Project_root should default to Rails.root And the exception "errorClass" equals "RuntimeError" And the exception "message" starts with "handled string" And the event "metaData.request.url" ends with "/project_root/default" - And the "file" of the top project stackframe equals "app/controllers/project_root_controller.rb" + And the "file" of the top non-bugsnag stackframe equals "app/controllers/project_root_controller.rb" Examples: | ruby_version | rails_version | @@ -49,7 +49,7 @@ Scenario Outline: Project_root can be set in an initializer And the exception "errorClass" equals "RuntimeError" And the exception "message" starts with "handled string" And the event "metaData.request.url" ends with "/project_root/initializer" - And the "file" of the top project stackframe equals "/usr/src/app/controllers/project_root_controller.rb" + And the "file" of the top non-bugsnag stackframe equals "/usr/src/app/controllers/project_root_controller.rb" Examples: | ruby_version | rails_version | @@ -79,7 +79,7 @@ Scenario Outline: Project_root can be set after an initializer And the exception "errorClass" equals "RuntimeError" And the exception "message" starts with "handled string" And the event "metaData.request.url" ends with "/project_root/after" - And the "file" of the top project stackframe equals "/usr/src/app/controllers/project_root_controller.rb" + And the "file" of the top non-bugsnag stackframe equals "/usr/src/app/controllers/project_root_controller.rb" Examples: | ruby_version | rails_version | diff --git a/features/steps/ruby_notifier_steps.rb b/features/steps/ruby_notifier_steps.rb index cbe9971b5..2160ae36d 100644 --- a/features/steps/ruby_notifier_steps.rb +++ b/features/steps/ruby_notifier_steps.rb @@ -3,38 +3,22 @@ When I set environment variable "#{env_var}" to "#{current_ip}" } end + When("I set environment variable {string} to the mock API port") do |env_var| steps %Q{ When I set environment variable "#{env_var}" to "#{MOCK_API_PORT}" } end + When("I set environment variable {string} to the proxy settings with credentials {string}") do |env_var, credentials| steps %Q{ When I set environment variable "#{env_var}" to "#{credentials}@#{current_ip}:#{MOCK_API_PORT}" } end -Then(/^the "(.+)" of the top project stackframe equals "(.+)"(?: for request (\d+))?$/) do |element, value, request_index| + +Then(/^the "(.+)" of the top non-bugsnag stackframe equals (\d+|".+")(?: for request (\d+))?$/) do |element, value, request_index| stacktrace = read_key_path(find_request(request_index)[:body], 'events.0.exceptions.0.stacktrace') - frame_index = 0 - stacktrace.each do |frame, index| - unless /.*lib\/bugsnag.*\.rb/.match(frame["file"]) - frame_index = index - break - end - end - steps %Q{ - the "#{element}" of stack frame #{frame_index} equals "#{value}" - } -end -Then(/^the "(.+)" of the top project stackframe equals (\d+)(?: for request (\d+))?$/) do |element, value, request_index| - stacktrace = read_key_path(find_request(request_index)[:body], 'events.0.exceptions.0.stacktrace') - frame_index = 0 - stacktrace.each do |frame, index| - unless /.*lib\/bugsnag.*\.rb/.match(frame["file"]) - frame_index = index - break - end - end + frame_index = stacktrace.find_index { |frame| ! /.*lib\/bugsnag.*\.rb/.match(frame["file"]) } steps %Q{ the "#{element}" of stack frame #{frame_index} equals #{value} } diff --git a/spec/report_spec.rb b/spec/report_spec.rb index 944d75228..97b5f8809 100644 --- a/spec/report_spec.rb +++ b/spec/report_spec.rb @@ -1074,7 +1074,15 @@ def gloops expect(frame["inProject"]).to be_nil end end - expect(bugsnag_count).to be > 0 + # Seven is used here as the called frames for a `notify` call should be: + # - Bugsnag.notify + # - Report.new + # - Report.initialize + # - Report.generate_exceptions_list + # - Report.generate_exceptions_list | raw_exceptions.map + # - Report.generate_exceptions_list | raw_exceptions.map | block + # - Report.generate_exceptions_list | raw_exceptions.map | block | Stacktrace.new + expect(bugsnag_count).to equal 7 } end From 0449c44130882cab7bd23782b86dc01957db7b0b Mon Sep 17 00:00:00 2001 From: Alex Moinet Date: Wed, 28 Nov 2018 17:30:33 +0000 Subject: [PATCH 11/13] Bugsnag frames in-project: Accounted for JRUBY stackframes differing in tests --- spec/report_spec.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/spec/report_spec.rb b/spec/report_spec.rb index 97b5f8809..32bcd4b39 100644 --- a/spec/report_spec.rb +++ b/spec/report_spec.rb @@ -1074,7 +1074,7 @@ def gloops expect(frame["inProject"]).to be_nil end end - # Seven is used here as the called frames for a `notify` call should be: + # 7 is used here as the called bugsnag frames for a `notify` call should be: # - Bugsnag.notify # - Report.new # - Report.initialize @@ -1082,7 +1082,13 @@ def gloops # - Report.generate_exceptions_list | raw_exceptions.map # - Report.generate_exceptions_list | raw_exceptions.map | block # - Report.generate_exceptions_list | raw_exceptions.map | block | Stacktrace.new - expect(bugsnag_count).to equal 7 + # However, JRUBY does not include the two `new` frames, resulting in 5 bugsnag frames + if defined?(JRUBY_VERSION) + frame_count = 5 + else + frame_count = 7 + end + expect(bugsnag_count).to equal frame_count } end From 4c5ea1a30f392ec46fc611566805eeb1b8231040 Mon Sep 17 00:00:00 2001 From: Alex Moinet Date: Thu, 29 Nov 2018 11:09:09 +0000 Subject: [PATCH 12/13] Bugsnag frames in-project: Separated notified strings tests out --- .../plain_features/handled_errors.feature | 62 ++++++++++++------- .../report_stack_frames.feature | 18 +++--- spec/stacktrace_spec.rb | 14 ++--- 3 files changed, 57 insertions(+), 37 deletions(-) diff --git a/features/plain_features/handled_errors.feature b/features/plain_features/handled_errors.feature index b81e83f95..2c5a0b360 100644 --- a/features/plain_features/handled_errors.feature +++ b/features/plain_features/handled_errors.feature @@ -4,10 +4,10 @@ Background: Given I set environment variable "BUGSNAG_API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" And I configure the bugsnag endpoint -Scenario Outline: A handled error sends a report +Scenario Outline: A rescued exception sends a report And I set environment variable "RUBY_VERSION" to "" And I have built the service "plain-ruby" - And I run the service "plain-ruby" with the command "bundle exec ruby handled/.rb" + And I run the service "plain-ruby" with the command "bundle exec ruby handled/notify_exception.rb" And I wait for 1 second Then I should receive a request And the request used the "Ruby Bugsnag Notifier" notifier @@ -17,25 +17,45 @@ Scenario Outline: A handled error sends a report And the event "severity" equals "warning" And the event "severityReason.type" equals "handledException" And the exception "errorClass" equals "RuntimeError" - And the "file" of the top non-bugsnag stackframe equals "/usr/src/app/handled/.rb" - And the "lineNumber" of the top non-bugsnag stackframe equals + And the "file" of stack frame 0 equals "/usr/src/app/handled/notify_exception.rb" + And the "lineNumber" of stack frame 0 equals 6 Examples: - | ruby version | file | lineNumber | - | 1.9.3 | notify_exception | 6 | - | 1.9.3 | notify_string | 8 | - | 2.0 | notify_exception | 6 | - | 2.0 | notify_string | 8 | - | 2.1 | notify_exception | 6 | - | 2.1 | notify_string | 8 | - | 2.2 | notify_exception | 6 | - | 2.2 | notify_string | 8 | - | 2.3 | notify_exception | 6 | - | 2.3 | notify_string | 8 | - | 2.4 | notify_exception | 6 | - | 2.4 | notify_string | 8 | - | 2.5 | notify_exception | 6 | - | 2.5 | notify_string | 8 | + | ruby version | + | 1.9.3 | + | 2.0 | + | 2.1 | + | 2.2 | + | 2.3 | + | 2.4 | + | 2.5 | + +Scenario Outline: A notified string sends a report + And I set environment variable "RUBY_VERSION" to "" + And I have built the service "plain-ruby" + And I run the service "plain-ruby" with the command "bundle exec ruby handled/notify_string.rb" + And I wait for 1 second + Then I should receive a request + And the request used the "Ruby Bugsnag Notifier" notifier + And the request used payload v4 headers + And the request contained the api key "a35a2a72bd230ac0aa0f52715bbdc6aa" + And the event "unhandled" is false + And the event "severity" equals "warning" + And the event "severityReason.type" equals "handledException" + And the exception "errorClass" equals "RuntimeError" + And the "file" of the top non-bugsnag stackframe equals "/usr/src/app/handled/notify_string.rb" + And the "lineNumber" of the top non-bugsnag stackframe equals 8 + + Examples: + | ruby version | + | 1.9.3 | + | 2.0 | + | 2.1 | + | 2.2 | + | 2.3 | + | 2.4 | + | 2.5 | + Scenario Outline: A handled error doesn't send a report when the :skip_bugsnag flag is set And I set environment variable "RUBY_VERSION" to "" @@ -67,8 +87,8 @@ Scenario Outline: A handled error can attach metadata in a block And the event "severity" equals "warning" And the event "severityReason.type" equals "handledException" And the exception "errorClass" equals "RuntimeError" - And the "file" of the top non-bugsnag stackframe equals "/usr/src/app/handled/block_metadata.rb" - And the "lineNumber" of the top non-bugsnag stackframe equals 6 + And the "file" of stack frame 0 equals "/usr/src/app/handled/block_metadata.rb" + And the "lineNumber" of stack frame 0 equals 6 And the event "metaData.account.id" equals "1234abcd" And the event "metaData.account.name" equals "Acme Co" And the event "metaData.account.support" is true diff --git a/features/plain_features/report_stack_frames.feature b/features/plain_features/report_stack_frames.feature index c6c6a5652..96729e3ca 100644 --- a/features/plain_features/report_stack_frames.feature +++ b/features/plain_features/report_stack_frames.feature @@ -45,17 +45,17 @@ Scenario Outline: Stack frames can be removed And the request used payload v4 headers And the request contained the api key "a35a2a72bd230ac0aa0f52715bbdc6aa" And the "file" of the top non-bugsnag stackframe equals "/usr/src/app/stack_frame_modification/initiators/handled_block.rb" - And the "lineNumber" of the top non-bugsnag stackframe equals + And the "lineNumber" of the top non-bugsnag stackframe equals 19 Examples: - | ruby version | lineNumber | - | 1.9.3 | 19 | - | 2.0 | 19 | - | 2.1 | 19 | - | 2.2 | 19 | - | 2.3 | 19 | - | 2.4 | 19 | - | 2.5 | 19 | + | ruby version | + | 1.9.3 | + | 2.0 | + | 2.1 | + | 2.2 | + | 2.3 | + | 2.4 | + | 2.5 | Scenario Outline: Stack frames can be marked as in project Given I set environment variable "RUBY_VERSION" to "" diff --git a/spec/stacktrace_spec.rb b/spec/stacktrace_spec.rb index 44caf934c..57895f2b2 100644 --- a/spec/stacktrace_spec.rb +++ b/spec/stacktrace_spec.rb @@ -18,13 +18,13 @@ exception = get_exception_from_payload(payload) starting_line = __LINE__ - 13 expect(exception["stacktrace"][0]["code"]).to eq({ - (starting_line + 0).to_s => " _a = 1", - (starting_line + 1).to_s => " _b = 2", - (starting_line + 2).to_s => " _c = 3", - (starting_line + 3).to_s => " \"Test\".prepnd \"T\"", - (starting_line + 4).to_s => " _d = 4", - (starting_line + 5).to_s => " _e = 5", - (starting_line + 6).to_s => " _f = 6" + (starting_line + 0).to_s => ' _a = 1', + (starting_line + 1).to_s => ' _b = 2', + (starting_line + 2).to_s => ' _c = 3', + (starting_line + 3).to_s => ' "Test".prepnd "T"', + (starting_line + 4).to_s => ' _d = 4', + (starting_line + 5).to_s => ' _e = 5', + (starting_line + 6).to_s => ' _f = 6' }) } end From 3256f779d0673f4e393374720ecdadebb07551c2 Mon Sep 17 00:00:00 2001 From: Alex Moinet Date: Thu, 29 Nov 2018 18:43:01 +0000 Subject: [PATCH 13/13] Bugsnag frames in-project: Make scenario names more explicit --- features/plain_features/report_stack_frames.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/plain_features/report_stack_frames.feature b/features/plain_features/report_stack_frames.feature index 96729e3ca..71c7497c1 100644 --- a/features/plain_features/report_stack_frames.feature +++ b/features/plain_features/report_stack_frames.feature @@ -34,7 +34,7 @@ Scenario Outline: Stack frames can be removed | 2.5 | handled_before_notify | 20 | | 2.5 | unhandled_before_notify | 21 | -Scenario Outline: Stack frames can be removed +Scenario Outline: Stack frames can be removed from a notified string Given I set environment variable "RUBY_VERSION" to "" And I set environment variable "CALLBACK_INITIATOR" to "handled_block" And I have built the service "plain-ruby"