exception_handling 2.5.1.pre.1 → 2.8.0.pre.1
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/.gitignore +1 -1
- data/.jenkins/Jenkinsfile +24 -8
- data/.rspec +3 -0
- data/CHANGELOG.md +19 -2
- data/Gemfile +4 -4
- data/Gemfile.lock +67 -58
- data/Rakefile +7 -6
- data/gemfiles/rails_4.gemfile +4 -4
- data/gemfiles/rails_5.gemfile +4 -4
- data/gemfiles/rails_6.gemfile +4 -4
- data/lib/exception_handling.rb +5 -2
- data/lib/exception_handling/exception_info.rb +3 -6
- data/lib/exception_handling/log_stub_error.rb +2 -1
- data/lib/exception_handling/logging_methods.rb +27 -0
- data/lib/exception_handling/methods.rb +6 -53
- data/lib/exception_handling/testing.rb +20 -10
- data/lib/exception_handling/version.rb +1 -1
- data/{test → spec}/helpers/controller_helpers.rb +0 -0
- data/{test → spec}/helpers/exception_helpers.rb +2 -2
- data/{test → spec}/rake_test_warning_false.rb +0 -0
- data/{test/test_helper.rb → spec/spec_helper.rb} +50 -39
- data/spec/unit/exception_handling/exception_catalog_spec.rb +85 -0
- data/spec/unit/exception_handling/exception_description_spec.rb +82 -0
- data/{test/unit/exception_handling/exception_info_test.rb → spec/unit/exception_handling/exception_info_spec.rb} +118 -99
- data/{test/unit/exception_handling/honeybadger_callbacks_test.rb → spec/unit/exception_handling/honeybadger_callbacks_spec.rb} +20 -20
- data/{test/unit/exception_handling/log_error_stub_test.rb → spec/unit/exception_handling/log_error_stub_spec.rb} +38 -22
- data/spec/unit/exception_handling/logging_methods_spec.rb +38 -0
- data/{test/unit/exception_handling/mailer_test.rb → spec/unit/exception_handling/mailer_spec.rb} +17 -17
- data/spec/unit/exception_handling/methods_spec.rb +105 -0
- data/spec/unit/exception_handling/sensu_spec.rb +51 -0
- data/{test/unit/exception_handling_test.rb → spec/unit/exception_handling_spec.rb} +348 -329
- metadata +32 -28
- data/test/unit/exception_handling/exception_catalog_test.rb +0 -85
- data/test/unit/exception_handling/exception_description_test.rb +0 -82
- data/test/unit/exception_handling/methods_test.rb +0 -84
- data/test/unit/exception_handling/sensu_test.rb +0 -52
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path('../../spec_helper', __dir__)
|
4
|
+
|
5
|
+
module ExceptionHandling
|
6
|
+
describe ExceptionDescription do
|
7
|
+
|
8
|
+
context "Filter" do
|
9
|
+
it "allow direct matching of strings" do
|
10
|
+
@f = ExceptionDescription.new(:filter1, error: "my error message")
|
11
|
+
expect(@f.match?('error' => "my error message")).to be_truthy
|
12
|
+
end
|
13
|
+
|
14
|
+
it "allow direct matching of strings on with symbol keys" do
|
15
|
+
@f = ExceptionDescription.new(:filter1, error: "my error message")
|
16
|
+
expect(@f.match?(error: "my error message")).to be_truthy
|
17
|
+
end
|
18
|
+
|
19
|
+
it "allow wildcards to cross line boundries" do
|
20
|
+
@f = ExceptionDescription.new(:filter1, error: "my error message.*with multiple lines")
|
21
|
+
expect(@f.match?(error: "my error message\nwith more than one, with multiple lines")).to be_truthy
|
22
|
+
end
|
23
|
+
|
24
|
+
it "complain when no regexps have a value" do
|
25
|
+
expect { ExceptionDescription.new(:filter1, error: nil) }.to raise_exception(ArgumentError, /has all blank regexes/)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "report when an invalid key is passed" do
|
29
|
+
expect { ExceptionDescription.new(:filter1, error: "my error message", not_a_parameter: false) }.to raise_exception(ArgumentError, "Unknown section: not_a_parameter")
|
30
|
+
end
|
31
|
+
|
32
|
+
it "allow send_to_honeybadger to be specified and have it disabled by default" do
|
33
|
+
expect(!ExceptionDescription.new(:filter1, error: "my error message", send_to_honeybadger: false).send_to_honeybadger).to be_truthy
|
34
|
+
expect(ExceptionDescription.new(:filter1, error: "my error message", send_to_honeybadger: true).send_to_honeybadger).to be_truthy
|
35
|
+
expect(!ExceptionDescription.new(:filter1, error: "my error message").send_to_honeybadger).to be_truthy
|
36
|
+
end
|
37
|
+
|
38
|
+
it "allow send_metric to be configured" do
|
39
|
+
expect(!ExceptionDescription.new(:filter1, error: "my error message", send_metric: false).send_metric).to be_truthy
|
40
|
+
expect(ExceptionDescription.new(:filter1, error: "my error message").send_metric).to be_truthy
|
41
|
+
end
|
42
|
+
|
43
|
+
it "provide metric name" do
|
44
|
+
expect(ExceptionDescription.new(:filter1, error: "my error message").metric_name).to eq("filter1")
|
45
|
+
expect(ExceptionDescription.new(:filter1, error: "my error message", metric_name: :some_other_metric_name).metric_name).to eq("some_other_metric_name")
|
46
|
+
end
|
47
|
+
|
48
|
+
it "replace spaces in metric name" do
|
49
|
+
@f = ExceptionDescription.new(:"filter has spaces", error: "my error message")
|
50
|
+
expect(@f.metric_name).to eq( "filter_has_spaces")
|
51
|
+
end
|
52
|
+
|
53
|
+
it "allow notes to be recorded" do
|
54
|
+
expect(ExceptionDescription.new(:filter1, error: "my error message").notes).to be_nil
|
55
|
+
expect(ExceptionDescription.new(:filter1, error: "my error message", notes: "a long string").notes).to eq("a long string")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "not consider config options in the filter set" do
|
59
|
+
expect(ExceptionDescription.new(:filter1, error: "my error message", send_metric: false).match?(error: "my error message")).to be_truthy
|
60
|
+
expect(ExceptionDescription.new(:filter1, error: "my error message", metric_name: "false").match?(error: "my error message")).to be_truthy
|
61
|
+
expect(ExceptionDescription.new(:filter1, error: "my error message", notes: "hey").match?(error: "my error message")).to be_truthy
|
62
|
+
end
|
63
|
+
|
64
|
+
it "provide exception details" do
|
65
|
+
exception_description = ExceptionDescription.new(:filter1, error: "my error message", notes: "hey")
|
66
|
+
|
67
|
+
expected = { "send_metric" => true, "metric_name" => "filter1", "notes" => "hey" }
|
68
|
+
|
69
|
+
expect(exception_description.exception_data).to eq( expected)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "match multiple email addresses" do
|
73
|
+
mobi = "ExceptionHandling::Warning: LoginAttempt::IPAddressLocked: failed login for 'mcc@mobistreak.com'"
|
74
|
+
credit = "ExceptionHandling::Warning: LoginAttempt::IPAddressLocked: failed login for 'damon@thecreditpros.com'"
|
75
|
+
|
76
|
+
exception_description = ExceptionDescription.new(:filter1, error: "ExceptionHandling::Warning: LoginAttempt::IPAddressLocked: failed login for '(mcc\@mobistreak|damon\@thecreditpros).com'")
|
77
|
+
expect(exception_description.match?(error: mobi)).to be_truthy
|
78
|
+
expect(exception_description.match?(error: credit)).to be_truthy
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -1,58 +1,58 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require File.expand_path('../../
|
3
|
+
require File.expand_path('../../spec_helper', __dir__)
|
4
4
|
require_test_helper 'controller_helpers'
|
5
5
|
require_test_helper 'exception_helpers'
|
6
6
|
|
7
7
|
module ExceptionHandling
|
8
|
-
|
8
|
+
describe ExceptionInfo do
|
9
9
|
include ControllerHelpers
|
10
10
|
include ExceptionHelpers
|
11
11
|
|
12
12
|
context "initialize" do
|
13
|
-
|
13
|
+
before do
|
14
14
|
@exception = StandardError.new("something went wrong")
|
15
15
|
@timestamp = Time.now
|
16
16
|
@controller = Object.new
|
17
17
|
end
|
18
18
|
|
19
19
|
context "controller_from_context" do
|
20
|
-
|
20
|
+
it "extract controller from context when not specified explicitly" do
|
21
21
|
exception_context = {
|
22
22
|
"action_controller.instance" => @controller
|
23
23
|
}
|
24
24
|
exception_info = ExceptionInfo.new(@exception, exception_context, @timestamp)
|
25
|
-
|
25
|
+
expect(exception_info.controller).to eq(@controller)
|
26
26
|
end
|
27
27
|
|
28
|
-
|
28
|
+
it "prefer the explicit controller over the one from context" do
|
29
29
|
exception_context = {
|
30
30
|
"action_controller.instance" => Object.new
|
31
31
|
}
|
32
32
|
exception_info = ExceptionInfo.new(@exception, exception_context, @timestamp, controller: @controller)
|
33
|
-
|
34
|
-
|
33
|
+
expect(exception_info.controller).to eq(@controller)
|
34
|
+
expect(exception_info.controller).not_to eq(exception_context["action_controller.instance"])
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
it "leave controller unset when not included in the context hash" do
|
38
38
|
exception_info = ExceptionInfo.new(@exception, {}, @timestamp)
|
39
|
-
|
39
|
+
expect(exception_info.controller).to be_nil
|
40
40
|
end
|
41
41
|
|
42
|
-
|
42
|
+
it "leave controller unset when context is not in hash format" do
|
43
43
|
exception_info = ExceptionInfo.new(@exception, "string context", @timestamp)
|
44
|
-
|
44
|
+
expect(exception_info.controller).to be_nil
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
context "data" do
|
50
|
-
|
50
|
+
before do
|
51
51
|
@exception = StandardError.new("something went wrong")
|
52
52
|
@timestamp = Time.now
|
53
53
|
end
|
54
54
|
|
55
|
-
|
55
|
+
it "return a hash with exception specific data including context hash" do
|
56
56
|
exception_context = {
|
57
57
|
"rack.session" => {
|
58
58
|
user_id: 23,
|
@@ -73,17 +73,17 @@ module ExceptionHandling
|
|
73
73
|
}
|
74
74
|
}
|
75
75
|
|
76
|
-
|
76
|
+
expect(exception_info.data).to eq(expected_data)
|
77
77
|
end
|
78
78
|
|
79
|
-
|
79
|
+
it "generate exception data appropriately if exception message is nil" do
|
80
80
|
exception_info = ExceptionInfo.new(exception_with_nil_message, "custom context data", @timestamp)
|
81
81
|
exception_data = exception_info.data
|
82
|
-
|
83
|
-
|
82
|
+
expect(exception_data["error_string"]).to eq("RuntimeError: ")
|
83
|
+
expect(exception_data["error"]).to eq("RuntimeError: : custom context data")
|
84
84
|
end
|
85
85
|
|
86
|
-
|
86
|
+
it "return a hash with exception specific data including context string" do
|
87
87
|
exception_context = "custom context data"
|
88
88
|
exception_info = ExceptionInfo.new(@exception, exception_context, @timestamp)
|
89
89
|
expected_data = {
|
@@ -96,11 +96,10 @@ module ExceptionHandling
|
|
96
96
|
"message" => "custom context data"
|
97
97
|
}
|
98
98
|
}
|
99
|
-
|
100
|
-
assert_equal_with_diff expected_data, exception_info.data
|
99
|
+
expect(exception_info.data).to eq(expected_data)
|
101
100
|
end
|
102
101
|
|
103
|
-
|
102
|
+
it "not include enhanced data from controller or custom data callback" do
|
104
103
|
env = { server: "fe98" }
|
105
104
|
parameters = { advertiser_id: 435 }
|
106
105
|
session = { username: "jsmith" }
|
@@ -109,8 +108,8 @@ module ExceptionHandling
|
|
109
108
|
data_callback = ->(data) { data[:custom_section] = "value" }
|
110
109
|
exception_info = ExceptionInfo.new(@exception, "custom context data", @timestamp, controller: controller, data_callback: data_callback)
|
111
110
|
|
112
|
-
|
113
|
-
|
111
|
+
expect(exception_info).to_not receive(:extract_and_merge_controller_data)
|
112
|
+
expect(exception_info).to_not receive(:customize_from_data_callback)
|
114
113
|
expected_data = {
|
115
114
|
"error_class" => "StandardError",
|
116
115
|
"error_string" => "StandardError: something went wrong",
|
@@ -122,12 +121,12 @@ module ExceptionHandling
|
|
122
121
|
}
|
123
122
|
}
|
124
123
|
|
125
|
-
|
124
|
+
expect(exception_info.data).to eq(expected_data)
|
126
125
|
end
|
127
126
|
end
|
128
127
|
|
129
128
|
context "enhanced_data" do
|
130
|
-
|
129
|
+
before do
|
131
130
|
@exception = StandardError.new("something went wrong")
|
132
131
|
@timestamp = Time.now
|
133
132
|
@exception_context = {
|
@@ -145,13 +144,13 @@ module ExceptionHandling
|
|
145
144
|
@data_callback = ->(data) { data[:custom_section] = "check this out" }
|
146
145
|
end
|
147
146
|
|
148
|
-
|
147
|
+
it "not return a mutable object for the session" do
|
149
148
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
150
149
|
exception_info.enhanced_data["session"]["hello"] = "world"
|
151
|
-
|
150
|
+
expect(@controller.session["hello"]).to be_nil
|
152
151
|
end
|
153
152
|
|
154
|
-
|
153
|
+
it "return a hash with generic exception attributes as well as context data" do
|
155
154
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
156
155
|
expected_data = {
|
157
156
|
"error_class" => "StandardError",
|
@@ -164,19 +163,19 @@ module ExceptionHandling
|
|
164
163
|
"location" => { "file" => "<no backtrace>", "line" => nil }
|
165
164
|
}
|
166
165
|
|
167
|
-
|
166
|
+
expect(prepare_data(exception_info.enhanced_data)).to eq(expected_data)
|
168
167
|
end
|
169
168
|
|
170
|
-
|
169
|
+
it "generate exception data appropriately if exception message is nil" do
|
171
170
|
exception_with_nil_message = RuntimeError.new(nil)
|
172
|
-
|
171
|
+
allow(exception_with_nil_message).to receive(:message).and_return(nil)
|
173
172
|
exception_info = ExceptionInfo.new(exception_with_nil_message, @exception_context, @timestamp)
|
174
173
|
exception_data = exception_info.enhanced_data
|
175
|
-
|
176
|
-
|
174
|
+
expect(exception_data["error_string"]).to eq("RuntimeError: ")
|
175
|
+
expect(exception_data["error"]).to eq("RuntimeError: ")
|
177
176
|
end
|
178
177
|
|
179
|
-
|
178
|
+
it "include controller data when available" do
|
180
179
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: @controller)
|
181
180
|
expected_data = {
|
182
181
|
"error_class" => "StandardError",
|
@@ -194,10 +193,10 @@ module ExceptionHandling
|
|
194
193
|
"location" => { "controller" => "dummy", "action" => "fail", "file" => "<no backtrace>", "line" => nil }
|
195
194
|
}
|
196
195
|
|
197
|
-
|
196
|
+
expect(prepare_data(exception_info.enhanced_data)).to eq(expected_data)
|
198
197
|
end
|
199
198
|
|
200
|
-
|
199
|
+
it "extract controller from rack specific exception context when not provided explicitly" do
|
201
200
|
@exception_context["action_controller.instance"] = @controller
|
202
201
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
203
202
|
expected_data = {
|
@@ -216,10 +215,10 @@ module ExceptionHandling
|
|
216
215
|
"location" => { "controller" => "dummy", "action" => "fail", "file" => "<no backtrace>", "line" => nil }
|
217
216
|
}
|
218
217
|
|
219
|
-
|
218
|
+
expect(prepare_data(exception_info.enhanced_data)).to eq(expected_data)
|
220
219
|
end
|
221
220
|
|
222
|
-
|
221
|
+
it "add to_s attribute to specific sections that have their content in hash format" do
|
223
222
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: @controller)
|
224
223
|
expected_data = {
|
225
224
|
"error_class" => "StandardError",
|
@@ -245,10 +244,10 @@ module ExceptionHandling
|
|
245
244
|
"location" => { "controller" => "dummy", "action" => "fail", "file" => "<no backtrace>", "line" => nil }
|
246
245
|
}
|
247
246
|
|
248
|
-
|
247
|
+
expect(exception_info.enhanced_data).to eq(expected_data)
|
249
248
|
end
|
250
249
|
|
251
|
-
|
250
|
+
it "filter out sensitive parameters like passwords" do
|
252
251
|
@controller.request.parameters[:password] = "super_secret"
|
253
252
|
@controller.request.parameters[:user] = { "password" => "also super secret", "password_confirmation" => "also super secret" }
|
254
253
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: @controller)
|
@@ -261,10 +260,10 @@ module ExceptionHandling
|
|
261
260
|
"password_confirmation" => "[FILTERED]"
|
262
261
|
}
|
263
262
|
}
|
264
|
-
|
263
|
+
expect(exception_info.enhanced_data["request"]["params"]).to eq(expected_params)
|
265
264
|
end
|
266
265
|
|
267
|
-
|
266
|
+
it "include the changes from the custom data callback" do
|
268
267
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: nil, data_callback: @data_callback)
|
269
268
|
expected_data = {
|
270
269
|
"error_class" => "StandardError",
|
@@ -278,11 +277,11 @@ module ExceptionHandling
|
|
278
277
|
"location" => { "file" => "<no backtrace>", "line" => nil }
|
279
278
|
}
|
280
279
|
|
281
|
-
|
280
|
+
expect(prepare_data(exception_info.enhanced_data)).to eq(expected_data)
|
282
281
|
end
|
283
282
|
|
284
|
-
|
285
|
-
|
283
|
+
it "apply the custom_data_hook results" do
|
284
|
+
allow(ExceptionHandling).to receive(:custom_data_hook).and_return(->(data) { data[:custom_hook] = "changes from custom hook" })
|
286
285
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
287
286
|
expected_data = {
|
288
287
|
"error_class" => "StandardError",
|
@@ -296,35 +295,35 @@ module ExceptionHandling
|
|
296
295
|
"location" => { "file" => "<no backtrace>", "line" => nil }
|
297
296
|
}
|
298
297
|
|
299
|
-
|
298
|
+
expect(prepare_data(exception_info.enhanced_data)).to eq(expected_data)
|
300
299
|
end
|
301
300
|
|
302
|
-
|
301
|
+
it "log info if the custom data hook results in a nil message exception" do
|
303
302
|
ExceptionHandling.custom_data_hook = ->(_data) do
|
304
303
|
raise_exception_with_nil_message
|
305
304
|
end
|
306
305
|
log_info_messages = []
|
307
|
-
|
306
|
+
allow(ExceptionHandling.logger).to receive(:info).with(any_args) do |message, _|
|
308
307
|
log_info_messages << message
|
309
308
|
end
|
310
309
|
|
311
310
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
312
311
|
exception_info.enhanced_data
|
313
|
-
|
312
|
+
expect(log_info_messages.find { |message| message =~ /Unable to execute custom custom_data_hook callback/ }).to be_truthy
|
314
313
|
ExceptionHandling.custom_data_hook = nil
|
315
314
|
end
|
316
315
|
end
|
317
316
|
|
318
317
|
context "exception_description" do
|
319
|
-
|
318
|
+
it "return the exception description from the global exception filter list" do
|
320
319
|
exception = StandardError.new("No route matches")
|
321
320
|
exception_info = ExceptionInfo.new(exception, {}, Time.now)
|
322
321
|
description = exception_info.exception_description
|
323
|
-
|
324
|
-
|
322
|
+
expect(description).to_not be_nil
|
323
|
+
expect(description.filter_name).to eq(:NoRoute)
|
325
324
|
end
|
326
325
|
|
327
|
-
|
326
|
+
it "find the description when filter criteria includes section in hash format" do
|
328
327
|
env = { server: "fe98" }
|
329
328
|
parameters = { advertiser_id: 435, controller: "sessions", action: "fail" }
|
330
329
|
session = { username: "jsmith", id: "session_key" }
|
@@ -332,25 +331,25 @@ module ExceptionHandling
|
|
332
331
|
controller = create_dummy_controller(env, parameters, session, request_uri)
|
333
332
|
exception = StandardError.new("Request to click domain rejected")
|
334
333
|
exception_info = ExceptionInfo.new(exception, nil, Time.now, controller: controller)
|
335
|
-
|
334
|
+
expect(exception_info.enhanced_data[:request].is_a?(Hash)).to eq(true)
|
336
335
|
description = exception_info.exception_description
|
337
|
-
|
338
|
-
|
336
|
+
expect(description).to_not be_nil
|
337
|
+
expect(description.filter_name).to eq(:"Click Request Rejected")
|
339
338
|
end
|
340
339
|
|
341
|
-
|
340
|
+
it "return same description object for related errors (avoid reloading exception catalog from disk)" do
|
342
341
|
exception = StandardError.new("No route matches")
|
343
342
|
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
344
343
|
description = exception_info.exception_description
|
345
344
|
|
346
345
|
repeat_ex = StandardError.new("No route matches 2")
|
347
346
|
repeat_ex_info = ExceptionInfo.new(repeat_ex, nil, Time.now)
|
348
|
-
|
347
|
+
expect(repeat_ex_info.exception_description.object_id).to eq(description.object_id)
|
349
348
|
end
|
350
349
|
end
|
351
350
|
|
352
351
|
context "controller_name" do
|
353
|
-
|
352
|
+
before do
|
354
353
|
@exception = StandardError.new('something went wrong')
|
355
354
|
@timestamp = Time.now
|
356
355
|
@exception_context = {
|
@@ -362,7 +361,7 @@ module ExceptionHandling
|
|
362
361
|
}
|
363
362
|
end
|
364
363
|
|
365
|
-
|
364
|
+
it "return controller_name when controller is present" do
|
366
365
|
env = { server: 'fe98' }
|
367
366
|
parameters = { controller: 'some_controller' }
|
368
367
|
session = { username: 'smith' }
|
@@ -370,65 +369,85 @@ module ExceptionHandling
|
|
370
369
|
controller = create_dummy_controller(env, parameters, session, request_uri)
|
371
370
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: controller)
|
372
371
|
|
373
|
-
|
372
|
+
expect(exception_info.controller_name).to eq('some_controller')
|
374
373
|
end
|
375
374
|
|
376
|
-
|
375
|
+
it "return an empty string when controller is not present" do
|
377
376
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
378
377
|
|
379
|
-
|
378
|
+
expect(exception_info.controller_name).to eq('')
|
380
379
|
end
|
381
380
|
end
|
382
381
|
|
383
382
|
context "send_to_honeybadger?" do
|
384
|
-
|
385
|
-
|
383
|
+
it "be enabled when Honeybadger is defined and exception is not in the filter list" do
|
384
|
+
allow(ExceptionHandling).to receive(:honeybadger_defined?).and_return(true)
|
386
385
|
exception = StandardError.new("something went wrong")
|
387
386
|
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
388
|
-
|
389
|
-
|
387
|
+
expect(exception_info.exception_description).to be_nil
|
388
|
+
expect(exception_info.send_to_honeybadger?).to eq(true)
|
390
389
|
end
|
391
390
|
|
392
|
-
|
393
|
-
|
391
|
+
it "be enabled when Honeybadger is defined and exception is on the filter list with the flag turned on" do
|
392
|
+
allow(ExceptionHandling).to receive(:honeybadger_defined?).and_return(true)
|
394
393
|
exception = StandardError.new("No route matches")
|
395
394
|
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
396
|
-
|
397
|
-
|
398
|
-
|
395
|
+
expect(exception_info.exception_description).to_not be_nil
|
396
|
+
expect(exception_info.exception_description.send_to_honeybadger).to eq(true)
|
397
|
+
expect(exception_info.send_to_honeybadger?).to eq(true)
|
399
398
|
end
|
400
399
|
|
401
|
-
|
402
|
-
|
400
|
+
it "be disabled when Honeybadger is defined and exception is on the filter list with the flag turned off" do
|
401
|
+
allow(ExceptionHandling).to receive(:honeybadger_defined?).and_return(true)
|
403
402
|
exception = StandardError.new("No route matches")
|
404
403
|
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
405
|
-
|
406
|
-
|
407
|
-
|
404
|
+
expect(exception_info.exception_description).to_not be_nil
|
405
|
+
allow(exception_info.exception_description).to receive(:send_to_honeybadger).and_return(false)
|
406
|
+
expect(exception_info.send_to_honeybadger?).to eq(false)
|
408
407
|
end
|
409
408
|
|
410
|
-
|
411
|
-
|
409
|
+
it "be disabled when Honeybadger is not defined" do
|
410
|
+
allow(ExceptionHandling).to receive(:honeybadger_defined?).and_return(false)
|
412
411
|
exception = StandardError.new("something went wrong")
|
413
412
|
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
414
|
-
|
415
|
-
|
413
|
+
expect(exception_info.exception_description).to be_nil
|
414
|
+
expect(exception_info.send_to_honeybadger?).to eq(false)
|
416
415
|
end
|
417
416
|
end
|
418
417
|
|
419
418
|
context "honeybadger_context_data" do
|
420
|
-
|
419
|
+
before do
|
420
|
+
allow(ExceptionHandling.logger).to receive(:current_context_for_thread).and_return({ cuid: 'ABCD' })
|
421
|
+
end
|
422
|
+
|
423
|
+
it "include thread_context when log_context: is nil" do
|
424
|
+
exception_with_nil_message = RuntimeError.new(nil)
|
425
|
+
allow(exception_with_nil_message).to receive(:message).and_return(nil)
|
426
|
+
exception_info = ExceptionInfo.new(exception_with_nil_message, @exception_context, @timestamp)
|
427
|
+
honeybadger_context_data = exception_info.honeybadger_context_data
|
428
|
+
expect(honeybadger_context_data[:log_context]).to eq({ "cuid" => 'ABCD' })
|
429
|
+
end
|
430
|
+
|
431
|
+
it "include thread context merged with log_context:" do
|
432
|
+
exception_with_nil_message = RuntimeError.new(nil)
|
433
|
+
allow(exception_with_nil_message).to receive(:message).and_return(nil)
|
434
|
+
exception_info = ExceptionInfo.new(exception_with_nil_message, @exception_context, @timestamp, log_context: { url: 'http://example.com' })
|
435
|
+
honeybadger_context_data = exception_info.honeybadger_context_data
|
436
|
+
expect(honeybadger_context_data[:log_context]).to eq({ "cuid" => 'ABCD', "url" => 'http://example.com' })
|
437
|
+
end
|
438
|
+
|
439
|
+
it "return the error details and relevant context data to be used as honeybadger notification context while filtering sensitive data" do
|
421
440
|
env = { server: "fe98" }
|
422
441
|
parameters = { advertiser_id: 435 }
|
423
442
|
session = { username: "jsmith" }
|
424
443
|
request_uri = "host/path"
|
425
444
|
controller = create_dummy_controller(env, parameters, session, request_uri)
|
426
|
-
|
445
|
+
allow(ExceptionHandling).to receive(:server_name).and_return("invoca_fe98")
|
427
446
|
|
428
447
|
exception = StandardError.new("Some Exception")
|
429
448
|
exception.set_backtrace([
|
430
|
-
"
|
431
|
-
"
|
449
|
+
"spec/unit/exception_handling_test.rb:847:in `exception_1'",
|
450
|
+
"spec/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"
|
432
451
|
])
|
433
452
|
exception_context = { "SERVER_NAME" => "exceptional.com" }
|
434
453
|
data_callback = ->(data) do
|
@@ -446,7 +465,6 @@ module ExceptionHandling
|
|
446
465
|
exception_context: { "SERVER_NAME" => "exceptional.com" },
|
447
466
|
server: "invoca_fe98",
|
448
467
|
scm_revision: "5b24eac37aaa91f5784901e9aabcead36fd9df82",
|
449
|
-
notes: "this is used by a test",
|
450
468
|
user_details: { "username" => "jsmith" },
|
451
469
|
request: {
|
452
470
|
"params" => { "advertiser_id" => 435 },
|
@@ -461,28 +479,30 @@ module ExceptionHandling
|
|
461
479
|
"SERVER_NAME" => "exceptional.com"
|
462
480
|
},
|
463
481
|
backtrace: [
|
464
|
-
"
|
465
|
-
"
|
482
|
+
"spec/unit/exception_handling_test.rb:847:in `exception_1'",
|
483
|
+
"spec/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"
|
466
484
|
],
|
467
|
-
event_response: "Event successfully received"
|
485
|
+
event_response: "Event successfully received",
|
486
|
+
log_context: { "cuid" => "ABCD" },
|
487
|
+
notes: "this is used by a test"
|
468
488
|
}
|
469
|
-
|
489
|
+
expect(exception_info.honeybadger_context_data).to eq(expected_data)
|
470
490
|
end
|
471
491
|
|
472
492
|
[['Hash', { 'cookie' => 'cookie_context' }],
|
473
493
|
['String', 'Entering Error State'],
|
474
494
|
['Array', ['Error1', 'Error2']]].each do |klass, value|
|
475
|
-
|
495
|
+
it "extract context from exception_context when it is a #{klass}" do
|
476
496
|
exception = StandardError.new("Exception")
|
477
497
|
exception_context = value
|
478
498
|
exception_info = ExceptionInfo.new(exception, exception_context, Time.now)
|
479
499
|
|
480
|
-
|
481
|
-
|
500
|
+
expect(value.class.name).to eq(klass)
|
501
|
+
expect(exception_info.honeybadger_context_data[:exception_context]).to eq(value)
|
482
502
|
end
|
483
503
|
end
|
484
504
|
|
485
|
-
|
505
|
+
it "filter out sensitive data from exception context such as [password, password_confirmation, oauth_token]" do
|
486
506
|
sensitive_data = {
|
487
507
|
"password" => "super_secret",
|
488
508
|
"password_confirmation" => "super_secret_confirmation",
|
@@ -517,15 +537,14 @@ module ExceptionHandling
|
|
517
537
|
}
|
518
538
|
}.merge(expected_sensitive_data)
|
519
539
|
|
520
|
-
|
540
|
+
expect(exception_info.honeybadger_context_data[:exception_context]).to eq(expected_exception_context)
|
521
541
|
end
|
522
542
|
|
523
|
-
|
543
|
+
it "omit context if exception_context is empty" do
|
524
544
|
exception = StandardError.new("Exception")
|
525
545
|
exception_context = ""
|
526
546
|
exception_info = ExceptionInfo.new(exception, exception_context, Time.now)
|
527
|
-
|
528
|
-
assert_nil exception_info.honeybadger_context_data[:exception_context]
|
547
|
+
expect(exception_info.honeybadger_context_data[:exception_context]).to be_nil
|
529
548
|
end
|
530
549
|
end
|
531
550
|
|