bugsnag 2.5.1 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/README.md +10 -0
- data/VERSION +1 -1
- data/bugsnag.gemspec +1 -0
- data/lib/bugsnag.rb +4 -1
- data/lib/bugsnag/configuration.rb +6 -0
- data/lib/bugsnag/delivery.rb +18 -0
- data/lib/bugsnag/delivery/synchronous.rb +25 -0
- data/lib/bugsnag/delivery/thread_queue.rb +51 -0
- data/lib/bugsnag/notification.rb +55 -37
- data/lib/bugsnag/rack.rb +2 -2
- data/lib/bugsnag/rails.rb +28 -12
- data/lib/bugsnag/rails/action_controller_rescue.rb +28 -0
- data/lib/bugsnag/rake.rb +2 -0
- data/lib/bugsnag/resque.rb +1 -1
- data/spec/code_spec.rb +96 -0
- data/spec/fixtures/crashes/end_of_file.rb +9 -0
- data/spec/fixtures/crashes/short_file.rb +1 -0
- data/spec/fixtures/crashes/start_of_file.rb +9 -0
- data/spec/integration_spec.rb +1 -0
- data/spec/middleware_spec.rb +41 -39
- data/spec/notification_spec.rb +281 -275
- data/spec/rack_spec.rb +10 -9
- data/spec/spec_helper.rb +26 -6
- metadata +23 -3
- data/lib/bugsnag/queue.rb +0 -36
data/lib/bugsnag/rake.rb
CHANGED
data/lib/bugsnag/resque.rb
CHANGED
@@ -26,7 +26,7 @@ module Bugsnag
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def save
|
29
|
-
Bugsnag.auto_notify(exception, {:context => "resque##{queue}", :payload => payload})
|
29
|
+
Bugsnag.auto_notify(exception, {:context => "resque##{queue}", :payload => payload, :delivery_method => :synchronous})
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
data/spec/code_spec.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Bugsnag::Notification do
|
4
|
+
it "includes code in the stack trace" do
|
5
|
+
_a = 1
|
6
|
+
_b = 2
|
7
|
+
_c = 3
|
8
|
+
notify_test_exception
|
9
|
+
_d = 4
|
10
|
+
_e = 5
|
11
|
+
_f = 6
|
12
|
+
|
13
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
14
|
+
exception = get_exception_from_payload(payload)
|
15
|
+
starting_line = __LINE__ - 10
|
16
|
+
expect(exception["stacktrace"][1]["code"]).to eq({
|
17
|
+
(starting_line + 0).to_s => " _a = 1",
|
18
|
+
(starting_line + 1).to_s => " _b = 2",
|
19
|
+
(starting_line + 2).to_s => " _c = 3",
|
20
|
+
(starting_line + 3).to_s => " notify_test_exception",
|
21
|
+
(starting_line + 4).to_s => " _d = 4",
|
22
|
+
(starting_line + 5).to_s => " _e = 5",
|
23
|
+
(starting_line + 6).to_s => " _f = 6"
|
24
|
+
})
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
it "allows you to disable sending code" do
|
29
|
+
Bugsnag.configuration.send_code = false
|
30
|
+
|
31
|
+
notify_test_exception
|
32
|
+
|
33
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
34
|
+
exception = get_exception_from_payload(payload)
|
35
|
+
expect(exception["stacktrace"][1]["code"]).to eq(nil)
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should send the first 7 lines of the file for exceptions near the top' do
|
40
|
+
load 'spec/fixtures/crashes/start_of_file.rb' rescue Bugsnag.notify $!
|
41
|
+
|
42
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
43
|
+
exception = get_exception_from_payload(payload)
|
44
|
+
|
45
|
+
expect(exception["stacktrace"][0]["code"]).to eq({
|
46
|
+
"1" => "#",
|
47
|
+
"2" => "raise 'hell'",
|
48
|
+
"3" => "#",
|
49
|
+
"4" => "#",
|
50
|
+
"5" => "#",
|
51
|
+
"6" => "#",
|
52
|
+
"7" => "#"
|
53
|
+
})
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should send the last 7 lines of the file for exceptions near the bottom' do
|
58
|
+
load 'spec/fixtures/crashes/end_of_file.rb' rescue Bugsnag.notify $!
|
59
|
+
|
60
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
61
|
+
exception = get_exception_from_payload(payload)
|
62
|
+
|
63
|
+
expect(exception["stacktrace"][0]["code"]).to eq({
|
64
|
+
"3" => "#",
|
65
|
+
"4" => "#",
|
66
|
+
"5" => "#",
|
67
|
+
"6" => "#",
|
68
|
+
"7" => "#",
|
69
|
+
"8" => "raise 'hell'",
|
70
|
+
"9" => "#"
|
71
|
+
})
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should send the last 7 lines of the file for exceptions near the bottom' do
|
76
|
+
load 'spec/fixtures/crashes/short_file.rb' rescue Bugsnag.notify $!
|
77
|
+
|
78
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
79
|
+
exception = get_exception_from_payload(payload)
|
80
|
+
|
81
|
+
expect(exception["stacktrace"][0]["code"]).to eq({
|
82
|
+
"1" => "raise 'hell'"
|
83
|
+
})
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should not send any code from unreadable files' do
|
88
|
+
eval("raise 'hell'", binding, "(eval)") rescue Bugsnag.notify $!
|
89
|
+
|
90
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
91
|
+
exception = get_exception_from_payload(payload)
|
92
|
+
|
93
|
+
expect(exception["stacktrace"][0]["code"]).to eq(nil)
|
94
|
+
}
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
raise 'hell'
|
data/spec/integration_spec.rb
CHANGED
data/spec/middleware_spec.rb
CHANGED
@@ -2,13 +2,6 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Bugsnag::MiddlewareStack do
|
4
4
|
it "runs before_bugsnag_notify callbacks, adding a tab" do
|
5
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
6
|
-
event = get_event_from_payload(payload)
|
7
|
-
expect(event[:metaData][:some_tab]).not_to be_nil
|
8
|
-
expect(event[:metaData][:some_tab][:info]).to eq("here")
|
9
|
-
expect(event[:metaData][:some_tab][:data]).to eq("also here")
|
10
|
-
end
|
11
|
-
|
12
5
|
callback_run_count = 0
|
13
6
|
Bugsnag.before_notify_callbacks << lambda {|notif|
|
14
7
|
notif.add_tab(:some_tab, {
|
@@ -20,16 +13,17 @@ describe Bugsnag::MiddlewareStack do
|
|
20
13
|
|
21
14
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
22
15
|
expect(callback_run_count).to eq(1)
|
23
|
-
end
|
24
16
|
|
25
|
-
|
26
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
17
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
27
18
|
event = get_event_from_payload(payload)
|
28
|
-
expect(event[
|
29
|
-
expect(event[
|
30
|
-
expect(event[
|
31
|
-
|
19
|
+
expect(event["metaData"]["some_tab"]).not_to be_nil
|
20
|
+
expect(event["metaData"]["some_tab"]["info"]).to eq("here")
|
21
|
+
expect(event["metaData"]["some_tab"]["data"]).to eq("also here")
|
22
|
+
}
|
23
|
+
|
24
|
+
end
|
32
25
|
|
26
|
+
it "runs before_bugsnag_notify callbacks, adding custom data" do
|
33
27
|
callback_run_count = 0
|
34
28
|
Bugsnag.before_notify_callbacks << lambda {|notif|
|
35
29
|
notif.add_custom_data(:info, "here")
|
@@ -40,18 +34,17 @@ describe Bugsnag::MiddlewareStack do
|
|
40
34
|
|
41
35
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
42
36
|
expect(callback_run_count).to eq(1)
|
43
|
-
end
|
44
37
|
|
45
|
-
|
46
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
38
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
47
39
|
event = get_event_from_payload(payload)
|
48
|
-
expect(event[
|
49
|
-
expect(event[
|
50
|
-
expect(event[
|
51
|
-
|
52
|
-
|
53
|
-
|
40
|
+
expect(event["metaData"]["custom"]).not_to be_nil
|
41
|
+
expect(event["metaData"]["custom"]["info"]).to eq("here")
|
42
|
+
expect(event["metaData"]["custom"]["data"]).to eq("also here")
|
43
|
+
}
|
44
|
+
|
45
|
+
end
|
54
46
|
|
47
|
+
it "runs before_bugsnag_notify callbacks, setting the user" do
|
55
48
|
callback_run_count = 0
|
56
49
|
Bugsnag.before_notify_callbacks << lambda {|notif|
|
57
50
|
notif.user = {:id => "here", :email => "also here", :name => "also here too", :random_key => "also here too too"}
|
@@ -60,15 +53,19 @@ describe Bugsnag::MiddlewareStack do
|
|
60
53
|
|
61
54
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
62
55
|
expect(callback_run_count).to eq(1)
|
56
|
+
|
57
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
58
|
+
event = get_event_from_payload(payload)
|
59
|
+
expect(event["user"]).not_to be_nil
|
60
|
+
expect(event["user"]["id"]).to eq("here")
|
61
|
+
expect(event["user"]["email"]).to eq("also here")
|
62
|
+
expect(event["user"]["name"]).to eq("also here too")
|
63
|
+
expect(event["user"]["random_key"]).to eq("also here too too")
|
64
|
+
}
|
65
|
+
|
63
66
|
end
|
64
67
|
|
65
68
|
it "overrides data set in before_notify" do
|
66
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
67
|
-
event = get_event_from_payload(payload)
|
68
|
-
expect(event[:metaData][:custom]).not_to be_nil
|
69
|
-
expect(event[:metaData][:custom][:info]).to eq("here2")
|
70
|
-
expect(event[:metaData][:custom][:data]).to eq("also here")
|
71
|
-
end
|
72
69
|
|
73
70
|
callback_run_count = 0
|
74
71
|
Bugsnag.before_notify_callbacks << lambda {|notif|
|
@@ -80,22 +77,26 @@ describe Bugsnag::MiddlewareStack do
|
|
80
77
|
|
81
78
|
Bugsnag.notify(BugsnagTestException.new("It crashed"), {:info => "here2"})
|
82
79
|
expect(callback_run_count).to eq(1)
|
80
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
81
|
+
event = get_event_from_payload(payload)
|
82
|
+
expect(event["metaData"]["custom"]).not_to be_nil
|
83
|
+
expect(event["metaData"]["custom"]["info"]).to eq("here2")
|
84
|
+
expect(event["metaData"]["custom"]["data"]).to eq("also here")
|
85
|
+
}
|
83
86
|
end
|
84
87
|
|
85
88
|
it "does not have have before or after callbacks by default" do
|
86
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
87
|
-
event = get_event_from_payload(payload)
|
88
|
-
expect(event[:metaData].size).to eq(0)
|
89
|
-
end
|
90
|
-
|
91
89
|
expect(Bugsnag.before_notify_callbacks.size).to eq(0)
|
92
90
|
expect(Bugsnag.after_notify_callbacks.size).to eq(0)
|
93
91
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
92
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
93
|
+
event = get_event_from_payload(payload)
|
94
|
+
expect(event["metaData"].size).to eq(0)
|
95
|
+
}
|
96
|
+
|
94
97
|
end
|
95
98
|
|
96
99
|
it "runs after_bugsnag_notify callbacks" do
|
97
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload)
|
98
|
-
|
99
100
|
callback_run_count = 0
|
100
101
|
Bugsnag.after_notify_callbacks << lambda {|notif|
|
101
102
|
callback_run_count += 1
|
@@ -104,6 +105,7 @@ describe Bugsnag::MiddlewareStack do
|
|
104
105
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
105
106
|
|
106
107
|
expect(callback_run_count).to eq(1)
|
108
|
+
expect(Bugsnag::Notification).to have_sent_notification
|
107
109
|
end
|
108
110
|
|
109
111
|
it "does not execute disabled bugsnag middleware" do
|
@@ -121,16 +123,14 @@ describe Bugsnag::MiddlewareStack do
|
|
121
123
|
end
|
122
124
|
|
123
125
|
it "does not notify if a callback told so" do
|
124
|
-
expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload)
|
125
126
|
Bugsnag.before_notify_callbacks << lambda do |notif|
|
126
127
|
notif.ignore!
|
127
128
|
end
|
128
129
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
130
|
+
expect(Bugsnag::Notification).not_to have_sent_notification
|
129
131
|
end
|
130
132
|
|
131
133
|
it "allows inspection of meta_data before ignoring exception" do
|
132
|
-
expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload)
|
133
|
-
|
134
134
|
# Use before notify callbacks as only the callback based metadata is
|
135
135
|
# available to before_notify_callbacks
|
136
136
|
Bugsnag.before_notify_callbacks << lambda do |notif|
|
@@ -142,5 +142,7 @@ describe Bugsnag::MiddlewareStack do
|
|
142
142
|
end
|
143
143
|
|
144
144
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
145
|
+
expect(Bugsnag::Notification).not_to have_sent_notification
|
146
|
+
|
145
147
|
end
|
146
148
|
end
|
data/spec/notification_spec.rb
CHANGED
@@ -28,49 +28,46 @@ class JRubyException
|
|
28
28
|
end
|
29
29
|
|
30
30
|
describe Bugsnag::Notification do
|
31
|
-
def notify_test_exception(*args)
|
32
|
-
Bugsnag.notify(RuntimeError.new("test message"), *args)
|
33
|
-
end
|
34
|
-
|
35
31
|
it "should contain an api_key if one is set" do
|
36
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
37
|
-
expect(payload[:apiKey]).to eq("c9d60ae4c7e70c4b6c4ebd3e8056d2b8")
|
38
|
-
end
|
39
|
-
|
40
32
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
33
|
+
|
34
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
35
|
+
expect(payload["apiKey"]).to eq("c9d60ae4c7e70c4b6c4ebd3e8056d2b8")
|
36
|
+
}
|
41
37
|
end
|
42
38
|
|
43
39
|
it "does not notify if api_key is not set" do
|
44
40
|
Bugsnag.configuration.api_key = nil
|
45
41
|
|
46
|
-
expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload)
|
47
|
-
|
48
42
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
43
|
+
|
44
|
+
expect(Bugsnag).not_to have_sent_notification
|
49
45
|
end
|
50
46
|
|
51
47
|
it "does not notify if api_key is empty" do
|
52
48
|
Bugsnag.configuration.api_key = ""
|
53
49
|
|
54
|
-
expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload)
|
55
|
-
|
56
50
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
51
|
+
|
52
|
+
expect(Bugsnag).not_to have_sent_notification
|
57
53
|
end
|
58
54
|
|
59
55
|
it "lets you override the api_key" do
|
60
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
61
|
-
expect(payload[:apiKey]).to eq("9d84383f9be2ca94902e45c756a9979d")
|
62
|
-
end
|
63
|
-
|
64
56
|
Bugsnag.notify(BugsnagTestException.new("It crashed"), :api_key => "9d84383f9be2ca94902e45c756a9979d")
|
57
|
+
|
58
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
59
|
+
expect(payload["apiKey"]).to eq("9d84383f9be2ca94902e45c756a9979d")
|
60
|
+
}
|
65
61
|
end
|
66
62
|
|
67
63
|
it "lets you override the groupingHash" do
|
68
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
69
|
-
event = get_event_from_payload(payload)
|
70
|
-
expect(event[:groupingHash]).to eq("this is my grouping hash")
|
71
|
-
end
|
72
64
|
|
73
65
|
Bugsnag.notify(BugsnagTestException.new("It crashed"), {:grouping_hash => "this is my grouping hash"})
|
66
|
+
|
67
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
68
|
+
event = get_event_from_payload(payload)
|
69
|
+
expect(event["groupingHash"]).to eq("this is my grouping hash")
|
70
|
+
}
|
74
71
|
end
|
75
72
|
|
76
73
|
it "uses the env variable apiKey" do
|
@@ -79,82 +76,78 @@ describe Bugsnag::Notification do
|
|
79
76
|
Bugsnag.instance_variable_set(:@configuration, Bugsnag::Configuration.new)
|
80
77
|
Bugsnag.configure do |config|
|
81
78
|
config.release_stage = "production"
|
82
|
-
|
83
|
-
|
84
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
85
|
-
expect(payload[:apiKey]).to eq("c9d60ae4c7e70c4b6c4ebd3e8056d2b9")
|
79
|
+
config.delivery_method = :synchronous
|
86
80
|
end
|
87
81
|
|
88
82
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
83
|
+
|
84
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
85
|
+
expect(payload["apiKey"]).to eq("c9d60ae4c7e70c4b6c4ebd3e8056d2b9")
|
86
|
+
}
|
89
87
|
end
|
90
88
|
|
91
89
|
it "has the right exception class" do
|
92
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
93
|
-
exception = get_exception_from_payload(payload)
|
94
|
-
expect(exception[:errorClass]).to eq("BugsnagTestException")
|
95
|
-
end
|
96
|
-
|
97
90
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
98
|
-
end
|
99
91
|
|
100
|
-
|
101
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
92
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
102
93
|
exception = get_exception_from_payload(payload)
|
103
|
-
expect(exception[
|
104
|
-
|
94
|
+
expect(exception["errorClass"]).to eq("BugsnagTestException")
|
95
|
+
}
|
96
|
+
end
|
105
97
|
|
98
|
+
it "has the right exception message" do
|
106
99
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
107
|
-
end
|
108
100
|
|
109
|
-
|
110
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
101
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
111
102
|
exception = get_exception_from_payload(payload)
|
112
|
-
expect(exception[
|
113
|
-
|
103
|
+
expect(exception["message"]).to eq("It crashed")
|
104
|
+
}
|
105
|
+
end
|
114
106
|
|
107
|
+
it "has a valid stacktrace" do
|
115
108
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
109
|
+
|
110
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
111
|
+
exception = get_exception_from_payload(payload)
|
112
|
+
expect(exception["stacktrace"].length).to be > 0
|
113
|
+
}
|
116
114
|
end
|
117
115
|
|
118
116
|
# TODO: nested context
|
119
117
|
|
120
118
|
it "accepts tabs in overrides and adds them to metaData" do
|
121
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
122
|
-
event = get_event_from_payload(payload)
|
123
|
-
expect(event[:metaData][:some_tab]).not_to be_nil
|
124
|
-
expect(event[:metaData][:some_tab][:info]).to eq("here")
|
125
|
-
expect(event[:metaData][:some_tab][:data]).to eq("also here")
|
126
|
-
end
|
127
|
-
|
128
119
|
Bugsnag.notify(BugsnagTestException.new("It crashed"), {
|
129
120
|
:some_tab => {
|
130
121
|
:info => "here",
|
131
122
|
:data => "also here"
|
132
123
|
}
|
133
124
|
})
|
134
|
-
end
|
135
125
|
|
136
|
-
|
137
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
126
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
138
127
|
event = get_event_from_payload(payload)
|
139
|
-
expect(event[
|
140
|
-
|
141
|
-
|
142
|
-
|
128
|
+
expect(event["metaData"]["some_tab"]).to eq(
|
129
|
+
"info" => "here",
|
130
|
+
"data" => "also here"
|
131
|
+
)
|
132
|
+
}
|
133
|
+
end
|
143
134
|
|
135
|
+
it "accepts non-hash overrides and adds them to the custom tab in metaData" do
|
144
136
|
Bugsnag.notify(BugsnagTestException.new("It crashed"), {
|
145
137
|
:info => "here",
|
146
138
|
:data => "also here"
|
147
139
|
})
|
148
|
-
end
|
149
140
|
|
150
|
-
|
151
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
141
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
152
142
|
event = get_event_from_payload(payload)
|
153
|
-
expect(event[
|
154
|
-
|
155
|
-
|
156
|
-
|
143
|
+
expect(event["metaData"]["custom"]).to eq(
|
144
|
+
"info" => "here",
|
145
|
+
"data" => "also here"
|
146
|
+
)
|
147
|
+
}
|
148
|
+
end
|
157
149
|
|
150
|
+
it "accepts meta data from an exception that mixes in Bugsnag::MetaData" do
|
158
151
|
exception = BugsnagTestExceptionWithMetaData.new("It crashed")
|
159
152
|
exception.bugsnag_meta_data = {
|
160
153
|
:some_tab => {
|
@@ -164,16 +157,17 @@ describe Bugsnag::Notification do
|
|
164
157
|
}
|
165
158
|
|
166
159
|
Bugsnag.notify(exception)
|
167
|
-
end
|
168
160
|
|
169
|
-
|
170
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
161
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
171
162
|
event = get_event_from_payload(payload)
|
172
|
-
expect(event[
|
173
|
-
|
174
|
-
|
175
|
-
|
163
|
+
expect(event["metaData"]["some_tab"]).to eq(
|
164
|
+
"info" => "here",
|
165
|
+
"data" => "also here"
|
166
|
+
)
|
167
|
+
}
|
168
|
+
end
|
176
169
|
|
170
|
+
it "accepts meta data from an exception that mixes in Bugsnag::MetaData, but override using the overrides" do
|
177
171
|
exception = BugsnagTestExceptionWithMetaData.new("It crashed")
|
178
172
|
exception.bugsnag_meta_data = {
|
179
173
|
:some_tab => {
|
@@ -183,64 +177,66 @@ describe Bugsnag::Notification do
|
|
183
177
|
}
|
184
178
|
|
185
179
|
Bugsnag.notify(exception, {:some_tab => {:info => "overridden"}})
|
186
|
-
end
|
187
180
|
|
188
|
-
|
189
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
181
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
190
182
|
event = get_event_from_payload(payload)
|
191
|
-
expect(event[
|
192
|
-
|
183
|
+
expect(event["metaData"]["some_tab"]).to eq(
|
184
|
+
"info" => "overridden",
|
185
|
+
"data" => "also here"
|
186
|
+
)
|
187
|
+
}
|
188
|
+
end
|
193
189
|
|
190
|
+
it "accepts user_id from an exception that mixes in Bugsnag::MetaData" do
|
194
191
|
exception = BugsnagTestExceptionWithMetaData.new("It crashed")
|
195
192
|
exception.bugsnag_user_id = "exception_user_id"
|
196
193
|
|
197
194
|
Bugsnag.notify(exception)
|
198
|
-
end
|
199
195
|
|
200
|
-
|
201
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
196
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
202
197
|
event = get_event_from_payload(payload)
|
203
|
-
expect(event[
|
204
|
-
|
198
|
+
expect(event["user"]["id"]).to eq("exception_user_id")
|
199
|
+
}
|
200
|
+
end
|
205
201
|
|
202
|
+
it "accepts user_id from an exception that mixes in Bugsnag::MetaData, but override using the overrides" do
|
206
203
|
exception = BugsnagTestExceptionWithMetaData.new("It crashed")
|
207
204
|
exception.bugsnag_user_id = "exception_user_id"
|
208
205
|
|
209
206
|
Bugsnag.notify(exception, {:user_id => "override_user_id"})
|
210
|
-
end
|
211
207
|
|
212
|
-
|
213
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
208
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
214
209
|
event = get_event_from_payload(payload)
|
215
|
-
expect(event[
|
216
|
-
|
210
|
+
expect(event["user"]["id"]).to eq("override_user_id")
|
211
|
+
}
|
212
|
+
end
|
217
213
|
|
214
|
+
it "accepts context from an exception that mixes in Bugsnag::MetaData" do
|
218
215
|
exception = BugsnagTestExceptionWithMetaData.new("It crashed")
|
219
216
|
exception.bugsnag_context = "exception_context"
|
220
217
|
|
221
218
|
Bugsnag.notify(exception)
|
219
|
+
|
220
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
221
|
+
event = get_event_from_payload(payload)
|
222
|
+
expect(event["context"]).to eq("exception_context")
|
223
|
+
}
|
222
224
|
end
|
223
225
|
|
224
226
|
it "accept contexts from an exception that mixes in Bugsnag::MetaData, but override using the overrides" do
|
225
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
226
|
-
event = get_event_from_payload(payload)
|
227
|
-
expect(event[:context]).to eq("override_context")
|
228
|
-
end
|
229
227
|
|
230
228
|
exception = BugsnagTestExceptionWithMetaData.new("It crashed")
|
231
229
|
exception.bugsnag_context = "exception_context"
|
232
230
|
|
233
231
|
Bugsnag.notify(exception, {:context => "override_context"})
|
234
|
-
end
|
235
232
|
|
236
|
-
|
237
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
233
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
238
234
|
event = get_event_from_payload(payload)
|
239
|
-
expect(event[
|
240
|
-
|
241
|
-
|
242
|
-
end
|
235
|
+
expect(event["context"]).to eq("override_context")
|
236
|
+
}
|
237
|
+
end
|
243
238
|
|
239
|
+
it "accepts meta_data in overrides (for backwards compatibility) and merge it into metaData" do
|
244
240
|
Bugsnag.notify(BugsnagTestException.new("It crashed"), {
|
245
241
|
:meta_data => {
|
246
242
|
:some_tab => {
|
@@ -249,15 +245,17 @@ describe Bugsnag::Notification do
|
|
249
245
|
}
|
250
246
|
}
|
251
247
|
})
|
248
|
+
|
249
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
250
|
+
event = get_event_from_payload(payload)
|
251
|
+
expect(event["metaData"]["some_tab"]).to eq(
|
252
|
+
"info" => "here",
|
253
|
+
"data" => "also here"
|
254
|
+
)
|
255
|
+
}
|
252
256
|
end
|
253
257
|
|
254
258
|
it "truncates large meta_data before sending" do
|
255
|
-
expect(Bugsnag::Notification).to receive(:do_post) do |endpoint, payload_string|
|
256
|
-
# Truncated body should be no bigger than
|
257
|
-
# 2 truncated hashes (4096*2) + rest of payload (5000)
|
258
|
-
expect(payload_string.length).to be < 4096*2 + 5000
|
259
|
-
end
|
260
|
-
|
261
259
|
Bugsnag.notify(BugsnagTestException.new("It crashed"), {
|
262
260
|
:meta_data => {
|
263
261
|
:some_tab => {
|
@@ -266,69 +264,76 @@ describe Bugsnag::Notification do
|
|
266
264
|
}
|
267
265
|
}
|
268
266
|
})
|
267
|
+
|
268
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
269
|
+
# Truncated body should be no bigger than
|
270
|
+
# 2 truncated hashes (4096*2) + rest of payload (5000)
|
271
|
+
expect(Bugsnag::Helpers.dump_json(payload).length).to be < 4096*2 + 10000
|
272
|
+
}
|
269
273
|
end
|
270
274
|
|
271
275
|
it "accepts a severity in overrides" do
|
272
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
273
|
-
event = get_event_from_payload(payload)
|
274
|
-
expect(event[:severity]).to eq("info")
|
275
|
-
end
|
276
|
-
|
277
276
|
Bugsnag.notify(BugsnagTestException.new("It crashed"), {
|
278
277
|
:severity => "info"
|
279
278
|
})
|
280
|
-
end
|
281
279
|
|
282
|
-
|
283
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
280
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
284
281
|
event = get_event_from_payload(payload)
|
285
|
-
expect(event[
|
286
|
-
|
282
|
+
expect(event["severity"]).to eq("info")
|
283
|
+
}
|
287
284
|
|
288
|
-
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
289
285
|
end
|
290
286
|
|
291
|
-
it "
|
292
|
-
|
287
|
+
it "defaults to warning severity" do
|
288
|
+
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
289
|
+
|
290
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
293
291
|
event = get_event_from_payload(payload)
|
294
|
-
expect(event[
|
295
|
-
|
292
|
+
expect(event["severity"]).to eq("warning")
|
293
|
+
}
|
294
|
+
end
|
296
295
|
|
296
|
+
it "does not accept a bad severity in overrides" do
|
297
297
|
Bugsnag.notify(BugsnagTestException.new("It crashed"), {
|
298
298
|
:severity => "fatal"
|
299
299
|
})
|
300
|
-
end
|
301
300
|
|
302
|
-
|
303
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
301
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
304
302
|
event = get_event_from_payload(payload)
|
305
|
-
expect(event[
|
306
|
-
|
303
|
+
expect(event["severity"]).to eq("warning")
|
304
|
+
}
|
305
|
+
end
|
307
306
|
|
307
|
+
it "autonotifies errors" do
|
308
308
|
Bugsnag.auto_notify(BugsnagTestException.new("It crashed"))
|
309
|
+
|
310
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
311
|
+
event = get_event_from_payload(payload)
|
312
|
+
expect(event["severity"]).to eq("error")
|
313
|
+
}
|
309
314
|
end
|
310
315
|
|
311
316
|
|
312
317
|
it "accepts a context in overrides" do
|
313
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
314
|
-
event = get_event_from_payload(payload)
|
315
|
-
expect(event[:context]).to eq("test_context")
|
316
|
-
end
|
317
|
-
|
318
318
|
Bugsnag.notify(BugsnagTestException.new("It crashed"), {
|
319
319
|
:context => "test_context"
|
320
320
|
})
|
321
|
-
end
|
322
321
|
|
323
|
-
|
324
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
322
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
325
323
|
event = get_event_from_payload(payload)
|
326
|
-
expect(event[
|
327
|
-
|
324
|
+
expect(event["context"]).to eq("test_context")
|
325
|
+
}
|
326
|
+
end
|
328
327
|
|
328
|
+
it "accepts a user_id in overrides" do
|
329
329
|
Bugsnag.notify(BugsnagTestException.new("It crashed"), {
|
330
330
|
:user_id => "test_user"
|
331
331
|
})
|
332
|
+
|
333
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
334
|
+
event = get_event_from_payload(payload)
|
335
|
+
expect(event["user"]["id"]).to eq("test_user")
|
336
|
+
}
|
332
337
|
end
|
333
338
|
|
334
339
|
it "does not send a notification if auto_notify is false" do
|
@@ -336,9 +341,9 @@ describe Bugsnag::Notification do
|
|
336
341
|
config.auto_notify = false
|
337
342
|
end
|
338
343
|
|
339
|
-
expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload)
|
340
|
-
|
341
344
|
Bugsnag.auto_notify(BugsnagTestException.new("It crashed"))
|
345
|
+
|
346
|
+
expect(Bugsnag).not_to have_sent_notification
|
342
347
|
end
|
343
348
|
|
344
349
|
it "contains a release_stage" do
|
@@ -346,160 +351,156 @@ describe Bugsnag::Notification do
|
|
346
351
|
config.release_stage = "production"
|
347
352
|
end
|
348
353
|
|
349
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
350
|
-
event = get_event_from_payload(payload)
|
351
|
-
expect(event[:app][:releaseStage]).to eq("production")
|
352
|
-
end
|
353
|
-
|
354
354
|
Bugsnag.auto_notify(BugsnagTestException.new("It crashed"))
|
355
|
+
|
356
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
357
|
+
event = get_event_from_payload(payload)
|
358
|
+
expect(event["app"]["releaseStage"]).to eq("production")
|
359
|
+
}
|
355
360
|
end
|
356
361
|
|
357
362
|
it "respects the notify_release_stages setting by not sending in development" do
|
358
|
-
expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload)
|
359
|
-
|
360
363
|
Bugsnag.configuration.notify_release_stages = ["production"]
|
361
364
|
Bugsnag.configuration.release_stage = "development"
|
362
365
|
|
363
366
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
367
|
+
|
368
|
+
expect(Bugsnag).not_to have_sent_notification
|
364
369
|
end
|
365
370
|
|
366
371
|
it "respects the notify_release_stages setting when set" do
|
367
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
368
|
-
exception = get_exception_from_payload(payload)
|
369
|
-
end
|
370
|
-
|
371
372
|
Bugsnag.configuration.release_stage = "development"
|
372
373
|
Bugsnag.configuration.notify_release_stages = ["development"]
|
373
374
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
375
|
+
|
376
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
377
|
+
event = get_event_from_payload(payload)
|
378
|
+
expect(event["exceptions"].length).to eq(1)
|
379
|
+
}
|
374
380
|
end
|
375
381
|
|
376
382
|
it "uses the https://notify.bugsnag.com endpoint by default" do
|
377
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
378
|
-
expect(endpoint).to eq("https://notify.bugsnag.com")
|
379
|
-
end
|
380
|
-
|
381
383
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
384
|
+
|
385
|
+
expect(WebMock).to have_requested(:post, "https://notify.bugsnag.com")
|
382
386
|
end
|
383
387
|
|
384
388
|
it "uses ssl when use_ssl is true" do
|
385
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
386
|
-
expect(endpoint).to start_with "https://"
|
387
|
-
end
|
388
|
-
|
389
389
|
Bugsnag.configuration.use_ssl = true
|
390
390
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
391
|
+
|
392
|
+
expect(WebMock).to have_requested(:post, "https://notify.bugsnag.com")
|
391
393
|
end
|
392
394
|
|
393
395
|
it "does not use ssl when use_ssl is false" do
|
394
|
-
|
395
|
-
expect(endpoint).to start_with "http://"
|
396
|
-
end
|
397
|
-
|
396
|
+
stub_request(:post, "http://notify.bugsnag.com/")
|
398
397
|
Bugsnag.configuration.use_ssl = false
|
399
398
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
399
|
+
|
400
|
+
expect(WebMock).to have_requested(:post, "http://notify.bugsnag.com")
|
400
401
|
end
|
401
402
|
|
402
403
|
it "uses ssl when use_ssl is unset" do
|
403
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
404
|
-
expect(endpoint).to start_with "https://"
|
405
|
-
end
|
406
|
-
|
407
404
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
405
|
+
|
406
|
+
expect(WebMock).to have_requested(:post, "https://notify.bugsnag.com")
|
408
407
|
end
|
409
408
|
|
410
409
|
it "does not mark the top-most stacktrace line as inProject if out of project" do
|
411
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
412
|
-
exception = get_exception_from_payload(payload)
|
413
|
-
expect(exception[:stacktrace].size).to be >= 1
|
414
|
-
expect(exception[:stacktrace].first[:inProject]).to be_nil
|
415
|
-
end
|
416
|
-
|
417
410
|
Bugsnag.configuration.project_root = "/Random/location/here"
|
418
411
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
419
|
-
end
|
420
412
|
|
421
|
-
|
422
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
413
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
423
414
|
exception = get_exception_from_payload(payload)
|
424
|
-
expect(exception[
|
425
|
-
expect(exception[
|
426
|
-
|
415
|
+
expect(exception["stacktrace"].size).to be >= 1
|
416
|
+
expect(exception["stacktrace"].first["inProject"]).to be_nil
|
417
|
+
}
|
418
|
+
end
|
427
419
|
|
420
|
+
it "marks the top-most stacktrace line as inProject if necessary" do
|
428
421
|
Bugsnag.configuration.project_root = File.expand_path File.dirname(__FILE__)
|
429
422
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
423
|
+
|
424
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
425
|
+
exception = get_exception_from_payload(payload)
|
426
|
+
expect(exception["stacktrace"].size).to be >= 1
|
427
|
+
expect(exception["stacktrace"].first["inProject"]).to eq(true)
|
428
|
+
}
|
430
429
|
end
|
431
430
|
|
432
431
|
it "adds app_version to the payload if it is set" do
|
433
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
434
|
-
event = get_event_from_payload(payload)
|
435
|
-
expect(event[:app][:version]).to eq("1.1.1")
|
436
|
-
end
|
437
|
-
|
438
432
|
Bugsnag.configuration.app_version = "1.1.1"
|
439
433
|
Bugsnag.notify(BugsnagTestException.new("It crashed"))
|
434
|
+
|
435
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
436
|
+
event = get_event_from_payload(payload)
|
437
|
+
expect(event["app"]["version"]).to eq("1.1.1")
|
438
|
+
}
|
440
439
|
end
|
441
440
|
|
442
441
|
it "filters params from all payload hashes if they are set in default params_filters" do
|
443
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
444
|
-
event = get_event_from_payload(payload)
|
445
|
-
expect(event[:metaData]).not_to be_nil
|
446
|
-
expect(event[:metaData][:request]).not_to be_nil
|
447
|
-
expect(event[:metaData][:request][:params]).not_to be_nil
|
448
|
-
expect(event[:metaData][:request][:params][:password]).to eq("[FILTERED]")
|
449
|
-
expect(event[:metaData][:request][:params][:other_password]).to eq("[FILTERED]")
|
450
|
-
expect(event[:metaData][:request][:params][:other_data]).to eq("123456")
|
451
|
-
end
|
452
442
|
|
453
443
|
Bugsnag.notify(BugsnagTestException.new("It crashed"), {:request => {:params => {:password => "1234", :other_password => "12345", :other_data => "123456"}}})
|
444
|
+
|
445
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
446
|
+
event = get_event_from_payload(payload)
|
447
|
+
expect(event["metaData"]).not_to be_nil
|
448
|
+
expect(event["metaData"]["request"]).not_to be_nil
|
449
|
+
expect(event["metaData"]["request"]["params"]).not_to be_nil
|
450
|
+
expect(event["metaData"]["request"]["params"]["password"]).to eq("[FILTERED]")
|
451
|
+
expect(event["metaData"]["request"]["params"]["other_password"]).to eq("[FILTERED]")
|
452
|
+
expect(event["metaData"]["request"]["params"]["other_data"]).to eq("123456")
|
453
|
+
}
|
454
454
|
end
|
455
455
|
|
456
456
|
it "filters params from all payload hashes if they are added to params_filters" do
|
457
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
458
|
-
event = get_event_from_payload(payload)
|
459
|
-
expect(event[:metaData]).not_to be_nil
|
460
|
-
expect(event[:metaData][:request]).not_to be_nil
|
461
|
-
expect(event[:metaData][:request][:params]).not_to be_nil
|
462
|
-
expect(event[:metaData][:request][:params][:password]).to eq("[FILTERED]")
|
463
|
-
expect(event[:metaData][:request][:params][:other_password]).to eq("[FILTERED]")
|
464
|
-
expect(event[:metaData][:request][:params][:other_data]).to eq("[FILTERED]")
|
465
|
-
end
|
466
457
|
|
467
458
|
Bugsnag.configuration.params_filters << "other_data"
|
468
459
|
Bugsnag.notify(BugsnagTestException.new("It crashed"), {:request => {:params => {:password => "1234", :other_password => "123456", :other_data => "123456"}}})
|
469
|
-
end
|
470
460
|
|
471
|
-
|
472
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
461
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
473
462
|
event = get_event_from_payload(payload)
|
474
|
-
expect(event[
|
475
|
-
expect(event[
|
476
|
-
expect(event[
|
477
|
-
expect(event[
|
478
|
-
|
463
|
+
expect(event["metaData"]).not_to be_nil
|
464
|
+
expect(event["metaData"]["request"]).not_to be_nil
|
465
|
+
expect(event["metaData"]["request"]["params"]).not_to be_nil
|
466
|
+
expect(event["metaData"]["request"]["params"]["password"]).to eq("[FILTERED]")
|
467
|
+
expect(event["metaData"]["request"]["params"]["other_password"]).to eq("[FILTERED]")
|
468
|
+
expect(event["metaData"]["request"]["params"]["other_data"]).to eq("[FILTERED]")
|
469
|
+
}
|
470
|
+
end
|
479
471
|
|
472
|
+
it "does not filter params from payload hashes if their values are nil" do
|
480
473
|
Bugsnag.notify(BugsnagTestException.new("It crashed"), {:request => {:params => {:nil_param => nil}}})
|
474
|
+
|
475
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
476
|
+
event = get_event_from_payload(payload)
|
477
|
+
expect(event["metaData"]).not_to be_nil
|
478
|
+
expect(event["metaData"]["request"]).not_to be_nil
|
479
|
+
expect(event["metaData"]["request"]["params"]).not_to be_nil
|
480
|
+
expect(event["metaData"]["request"]["params"]).to have_key("nil_param")
|
481
|
+
}
|
481
482
|
end
|
482
483
|
|
483
484
|
it "does not notify if the exception class is in the default ignore_classes list" do
|
484
|
-
expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload)
|
485
|
-
|
486
485
|
Bugsnag.notify_or_ignore(ActiveRecord::RecordNotFound.new("It crashed"))
|
486
|
+
|
487
|
+
expect(Bugsnag).not_to have_sent_notification
|
487
488
|
end
|
488
489
|
|
489
490
|
it "does not notify if the non-default exception class is added to the ignore_classes" do
|
490
491
|
Bugsnag.configuration.ignore_classes << "BugsnagTestException"
|
491
492
|
|
492
|
-
expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload)
|
493
|
-
|
494
493
|
Bugsnag.notify_or_ignore(BugsnagTestException.new("It crashed"))
|
494
|
+
|
495
|
+
expect(Bugsnag).not_to have_sent_notification
|
495
496
|
end
|
496
497
|
|
497
498
|
it "does not notify if exception's ancestor is an ignored class" do
|
498
499
|
Bugsnag.configuration.ignore_classes << "BugsnagTestException"
|
499
500
|
|
500
|
-
expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload)
|
501
|
-
|
502
501
|
Bugsnag.notify_or_ignore(BugsnagSubclassTestException.new("It crashed"))
|
502
|
+
|
503
|
+
expect(Bugsnag).not_to have_sent_notification
|
503
504
|
end
|
504
505
|
|
505
506
|
it "does not notify if any caused exception is an ignored class" do
|
@@ -508,35 +509,30 @@ describe Bugsnag::Notification do
|
|
508
509
|
ex = NestedException.new("Self-referential exception")
|
509
510
|
ex.original_exception = BugsnagTestException.new("It crashed")
|
510
511
|
|
511
|
-
expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload)
|
512
|
-
|
513
512
|
Bugsnag.notify_or_ignore(ex)
|
513
|
+
|
514
|
+
expect(Bugsnag).not_to have_sent_notification
|
514
515
|
end
|
515
516
|
|
516
517
|
it "accepts both String and Class instances as an ignored class" do
|
517
518
|
Bugsnag.configuration.ignore_classes << BugsnagTestException
|
518
519
|
|
519
|
-
expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload)
|
520
|
-
|
521
520
|
Bugsnag.notify_or_ignore(BugsnagTestException.new("It crashed"))
|
521
|
+
|
522
|
+
expect(Bugsnag).not_to have_sent_notification
|
522
523
|
end
|
523
524
|
|
524
525
|
it "does not notify if the user agent is present and matches a regex in ignore_user_agents" do
|
525
526
|
Bugsnag.configuration.ignore_user_agents << %r{BugsnagUserAgent}
|
526
527
|
|
527
|
-
expect(Bugsnag::Notification).not_to receive(:deliver_exception_payload)
|
528
|
-
|
529
528
|
((Thread.current["bugsnag_req_data"] ||= {})[:rack_env] ||= {})["HTTP_USER_AGENT"] = "BugsnagUserAgent"
|
530
529
|
|
531
530
|
Bugsnag.notify_or_ignore(BugsnagTestException.new("It crashed"))
|
531
|
+
|
532
|
+
expect(Bugsnag::Notification).not_to have_sent_notification
|
532
533
|
end
|
533
534
|
|
534
535
|
it "sends the cause of the exception" do
|
535
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
536
|
-
event = get_event_from_payload(payload)
|
537
|
-
expect(event[:exceptions].size).to eq(2)
|
538
|
-
end
|
539
|
-
|
540
536
|
begin
|
541
537
|
begin
|
542
538
|
raise "jiminey"
|
@@ -546,25 +542,26 @@ describe Bugsnag::Notification do
|
|
546
542
|
rescue
|
547
543
|
Bugsnag.notify $!
|
548
544
|
end
|
549
|
-
end
|
550
545
|
|
551
|
-
|
552
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
546
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
553
547
|
event = get_event_from_payload(payload)
|
554
|
-
expect(event[
|
555
|
-
|
548
|
+
expect(event["exceptions"].size).to eq(2)
|
549
|
+
}
|
550
|
+
end
|
556
551
|
|
552
|
+
it "does not unwrap the same exception twice" do
|
557
553
|
ex = NestedException.new("Self-referential exception")
|
558
554
|
ex.original_exception = ex
|
559
555
|
|
560
556
|
Bugsnag.notify_or_ignore(ex)
|
557
|
+
|
558
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
559
|
+
event = get_event_from_payload(payload)
|
560
|
+
expect(event["exceptions"].size).to eq(1)
|
561
|
+
}
|
561
562
|
end
|
562
563
|
|
563
564
|
it "does not unwrap more than 5 exceptions" do
|
564
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
565
|
-
event = get_event_from_payload(payload)
|
566
|
-
expect(event[:exceptions].size).to eq(5)
|
567
|
-
end
|
568
565
|
|
569
566
|
first_ex = ex = NestedException.new("Deep exception")
|
570
567
|
10.times do |idx|
|
@@ -572,26 +569,30 @@ describe Bugsnag::Notification do
|
|
572
569
|
end
|
573
570
|
|
574
571
|
Bugsnag.notify_or_ignore(first_ex)
|
572
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
573
|
+
event = get_event_from_payload(payload)
|
574
|
+
expect(event["exceptions"].size).to eq(5)
|
575
|
+
}
|
575
576
|
end
|
576
577
|
|
577
578
|
it "calls to_exception on i18n error objects" do
|
578
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
579
|
-
exception = get_exception_from_payload(payload)
|
580
|
-
expect(exception[:errorClass]).to eq("BugsnagTestException")
|
581
|
-
expect(exception[:message]).to eq("message")
|
582
|
-
end
|
583
|
-
|
584
579
|
Bugsnag.notify(OpenStruct.new(:to_exception => BugsnagTestException.new("message")))
|
585
|
-
end
|
586
580
|
|
587
|
-
|
588
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
581
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
589
582
|
exception = get_exception_from_payload(payload)
|
590
|
-
expect(exception[
|
591
|
-
expect(exception[
|
592
|
-
|
583
|
+
expect(exception["errorClass"]).to eq("BugsnagTestException")
|
584
|
+
expect(exception["message"]).to eq("message")
|
585
|
+
}
|
586
|
+
end
|
593
587
|
|
588
|
+
it "generates runtimeerror for non exceptions" do
|
594
589
|
notify_test_exception
|
590
|
+
|
591
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
592
|
+
exception = get_exception_from_payload(payload)
|
593
|
+
expect(exception["errorClass"]).to eq("RuntimeError")
|
594
|
+
expect(exception["message"]).to eq("test message")
|
595
|
+
}
|
595
596
|
end
|
596
597
|
|
597
598
|
it "supports unix-style paths in backtraces" do
|
@@ -601,22 +602,22 @@ describe Bugsnag::Notification do
|
|
601
602
|
"/Some/path/rspec/example.rb:113:in `instance_eval'"
|
602
603
|
])
|
603
604
|
|
604
|
-
|
605
|
-
exception = get_exception_from_payload(payload)
|
606
|
-
expect(exception[:stacktrace].length).to eq(2)
|
605
|
+
Bugsnag.notify(ex)
|
607
606
|
|
608
|
-
|
609
|
-
|
610
|
-
expect(
|
611
|
-
expect(line[:method]).to be nil
|
607
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
608
|
+
exception = get_exception_from_payload(payload)
|
609
|
+
expect(exception["stacktrace"].length).to eq(2)
|
612
610
|
|
613
|
-
line = exception[
|
614
|
-
expect(line[
|
615
|
-
expect(line[
|
616
|
-
expect(line[
|
617
|
-
end
|
611
|
+
line = exception["stacktrace"][0]
|
612
|
+
expect(line["file"]).to eq("/Users/james/app/spec/notification_spec.rb")
|
613
|
+
expect(line["lineNumber"]).to eq(419)
|
614
|
+
expect(line["method"]).to be nil
|
618
615
|
|
619
|
-
|
616
|
+
line = exception["stacktrace"][1]
|
617
|
+
expect(line["file"]).to eq("/Some/path/rspec/example.rb")
|
618
|
+
expect(line["lineNumber"]).to eq(113)
|
619
|
+
expect(line["method"]).to eq("instance_eval")
|
620
|
+
}
|
620
621
|
end
|
621
622
|
|
622
623
|
it "supports windows-style paths in backtraces" do
|
@@ -626,22 +627,22 @@ describe Bugsnag::Notification do
|
|
626
627
|
"C:/ruby/1.9.1/gems/actionpack-2.3.10/filters.rb:638:in `block in run_before_filters'"
|
627
628
|
])
|
628
629
|
|
629
|
-
|
630
|
-
exception = get_exception_from_payload(payload)
|
631
|
-
expect(exception[:stacktrace].length).to eq(2)
|
630
|
+
Bugsnag.notify(ex)
|
632
631
|
|
633
|
-
|
634
|
-
|
635
|
-
expect(
|
636
|
-
expect(line[:method]).to eq("index")
|
632
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
633
|
+
exception = get_exception_from_payload(payload)
|
634
|
+
expect(exception["stacktrace"].length).to eq(2)
|
637
635
|
|
638
|
-
line = exception[
|
639
|
-
expect(line[
|
640
|
-
expect(line[
|
641
|
-
expect(line[
|
642
|
-
end
|
636
|
+
line = exception["stacktrace"][0]
|
637
|
+
expect(line["file"]).to eq("C:/projects/test/app/controllers/users_controller.rb")
|
638
|
+
expect(line["lineNumber"]).to eq(13)
|
639
|
+
expect(line["method"]).to eq("index")
|
643
640
|
|
644
|
-
|
641
|
+
line = exception["stacktrace"][1]
|
642
|
+
expect(line["file"]).to eq("C:/ruby/1.9.1/gems/actionpack-2.3.10/filters.rb")
|
643
|
+
expect(line["lineNumber"]).to eq(638)
|
644
|
+
expect(line["method"]).to eq("block in run_before_filters")
|
645
|
+
}
|
645
646
|
end
|
646
647
|
|
647
648
|
it "uses a proxy host if configured" do
|
@@ -713,27 +714,32 @@ describe Bugsnag::Notification do
|
|
713
714
|
invalid_data = "fl\xc3ff"
|
714
715
|
invalid_data.force_encoding('BINARY') if invalid_data.respond_to?(:force_encoding)
|
715
716
|
|
716
|
-
expect(Bugsnag::Notification).to receive(:do_post) do |endpoint, payload_string|
|
717
|
-
expect(payload_string).to match(/fl�ff/) if defined?(Encoding::UTF_8)
|
718
|
-
end
|
719
|
-
|
720
717
|
notify_test_exception(:fluff => {:fluff => invalid_data})
|
718
|
+
|
719
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
720
|
+
if defined?(Encoding::UTF_8)
|
721
|
+
expect(payload.to_json).to match(/fl�ff/)
|
722
|
+
else
|
723
|
+
expect(payload.to_json).to match(/flff/)
|
724
|
+
end
|
725
|
+
}
|
721
726
|
end
|
722
727
|
|
723
728
|
if defined?(JRUBY_VERSION)
|
724
729
|
|
725
730
|
it "should work with java.lang.Throwables" do
|
726
|
-
expect(Bugsnag::Notification).to receive(:deliver_exception_payload) do |endpoint, payload|
|
727
|
-
expect(payload[:events][0][:exceptions][0][:errorClass]).to eq('Java::JavaLang::ArrayIndexOutOfBoundsException')
|
728
|
-
expect(payload[:events][0][:exceptions][0][:message]).to eq("2")
|
729
|
-
expect(payload[:events][0][:exceptions][0][:stacktrace].size).to be > 0
|
730
|
-
end
|
731
|
-
|
732
731
|
begin
|
733
732
|
JRubyException.raise!
|
734
733
|
rescue
|
735
734
|
Bugsnag.notify $!
|
736
735
|
end
|
736
|
+
|
737
|
+
expect(Bugsnag).to have_sent_notification{ |payload|
|
738
|
+
exception = get_exception_from_payload(payload)
|
739
|
+
expect(exception["errorClass"]).to eq('Java::JavaLang::ArrayIndexOutOfBoundsException')
|
740
|
+
expect(exception["message"]).to eq("2")
|
741
|
+
expect(exception["stacktrace"].size).to be > 0
|
742
|
+
}
|
737
743
|
end
|
738
744
|
end
|
739
745
|
end
|