exception_handling 3.0.pre.1 → 3.0.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 +5 -5
- data/.github/CODEOWNERS +1 -0
- data/.github/workflows/pipeline.yml +36 -0
- data/.gitignore +3 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -1
- data/.tool-versions +1 -0
- data/Appraisals +13 -0
- data/CHANGELOG.md +150 -0
- data/Gemfile +10 -16
- data/Gemfile.lock +65 -128
- data/README.md +51 -19
- data/Rakefile +8 -11
- data/exception_handling.gemspec +11 -13
- data/gemfiles/rails_5.gemfile +16 -0
- data/gemfiles/rails_6.gemfile +16 -0
- data/gemfiles/rails_7.gemfile +16 -0
- data/lib/exception_handling/escalate_callback.rb +19 -0
- data/lib/exception_handling/exception_info.rb +15 -11
- data/lib/exception_handling/log_stub_error.rb +2 -1
- data/lib/exception_handling/logging_methods.rb +21 -0
- data/lib/exception_handling/testing.rb +9 -12
- data/lib/exception_handling/version.rb +1 -1
- data/lib/exception_handling.rb +83 -173
- data/{test → spec}/helpers/exception_helpers.rb +2 -2
- data/spec/rake_test_warning_false.rb +20 -0
- data/{test/test_helper.rb → spec/spec_helper.rb} +63 -66
- data/spec/unit/exception_handling/escalate_callback_spec.rb +81 -0
- 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} +170 -114
- 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/spec/unit/exception_handling_spec.rb +1063 -0
- metadata +62 -91
- data/lib/exception_handling/honeybadger_callbacks.rb +0 -59
- data/lib/exception_handling/mailer.rb +0 -70
- data/lib/exception_handling/methods.rb +0 -101
- data/lib/exception_handling/sensu.rb +0 -28
- data/semaphore_ci/setup.sh +0 -3
- 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/honeybadger_callbacks_test.rb +0 -122
- data/test/unit/exception_handling/mailer_test.rb +0 -98
- data/test/unit/exception_handling/methods_test.rb +0 -84
- data/test/unit/exception_handling/sensu_test.rb +0 -52
- data/test/unit/exception_handling_test.rb +0 -1109
- data/views/exception_handling/mailer/escalate_custom.html.erb +0 -17
- data/views/exception_handling/mailer/escalation_notification.html.erb +0 -17
- data/views/exception_handling/mailer/log_parser_exception_notification.html.erb +0 -82
- /data/{test → spec}/helpers/controller_helpers.rb +0 -0
@@ -1,58 +1,75 @@
|
|
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
|
-
exception_info = ExceptionInfo.new(@exception, exception_context, @timestamp, @controller)
|
33
|
-
|
34
|
-
|
32
|
+
exception_info = ExceptionInfo.new(@exception, exception_context, @timestamp, controller: @controller)
|
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
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "honeybadger_tags" do
|
49
|
+
it "retrieved from log_context" do
|
50
|
+
exception_info = ExceptionInfo.new(@exception, "string context", @timestamp, log_context: { honeybadger_tags: ['Data-Services'] })
|
51
|
+
expect(exception_info.honeybadger_tags).to eq(['Data-Services'])
|
52
|
+
end
|
53
|
+
|
54
|
+
it "retrieved from log_context and normalized to array if a string" do
|
55
|
+
exception_info = ExceptionInfo.new(@exception, "string context", @timestamp, log_context: { honeybadger_tags: 'Data-Services' })
|
56
|
+
expect(exception_info.honeybadger_tags).to eq(['Data-Services'])
|
57
|
+
end
|
58
|
+
|
59
|
+
it "defaults to empty array if not given" do
|
60
|
+
exception_info = ExceptionInfo.new(@exception, "string context", @timestamp)
|
61
|
+
expect(exception_info.honeybadger_tags).to eq([])
|
45
62
|
end
|
46
63
|
end
|
47
64
|
end
|
48
65
|
|
49
66
|
context "data" do
|
50
|
-
|
67
|
+
before do
|
51
68
|
@exception = StandardError.new("something went wrong")
|
52
69
|
@timestamp = Time.now
|
53
70
|
end
|
54
71
|
|
55
|
-
|
72
|
+
it "return a hash with exception specific data including context hash" do
|
56
73
|
exception_context = {
|
57
74
|
"rack.session" => {
|
58
75
|
user_id: 23,
|
@@ -73,17 +90,17 @@ module ExceptionHandling
|
|
73
90
|
}
|
74
91
|
}
|
75
92
|
|
76
|
-
|
93
|
+
expect(exception_info.data).to eq(expected_data)
|
77
94
|
end
|
78
95
|
|
79
|
-
|
96
|
+
it "generate exception data appropriately if exception message is nil" do
|
80
97
|
exception_info = ExceptionInfo.new(exception_with_nil_message, "custom context data", @timestamp)
|
81
98
|
exception_data = exception_info.data
|
82
|
-
|
83
|
-
|
99
|
+
expect(exception_data["error_string"]).to eq("RuntimeError: ")
|
100
|
+
expect(exception_data["error"]).to eq("RuntimeError: : custom context data")
|
84
101
|
end
|
85
102
|
|
86
|
-
|
103
|
+
it "return a hash with exception specific data including context string" do
|
87
104
|
exception_context = "custom context data"
|
88
105
|
exception_info = ExceptionInfo.new(@exception, exception_context, @timestamp)
|
89
106
|
expected_data = {
|
@@ -96,21 +113,20 @@ module ExceptionHandling
|
|
96
113
|
"message" => "custom context data"
|
97
114
|
}
|
98
115
|
}
|
99
|
-
|
100
|
-
assert_equal_with_diff expected_data, exception_info.data
|
116
|
+
expect(exception_info.data).to eq(expected_data)
|
101
117
|
end
|
102
118
|
|
103
|
-
|
119
|
+
it "not include enhanced data from controller or custom data callback" do
|
104
120
|
env = { server: "fe98" }
|
105
121
|
parameters = { advertiser_id: 435 }
|
106
122
|
session = { username: "jsmith" }
|
107
123
|
request_uri = "host/path"
|
108
124
|
controller = create_dummy_controller(env, parameters, session, request_uri)
|
109
125
|
data_callback = ->(data) { data[:custom_section] = "value" }
|
110
|
-
exception_info = ExceptionInfo.new(@exception, "custom context data", @timestamp, controller, data_callback)
|
126
|
+
exception_info = ExceptionInfo.new(@exception, "custom context data", @timestamp, controller: controller, data_callback: data_callback)
|
111
127
|
|
112
|
-
|
113
|
-
|
128
|
+
expect(exception_info).to_not receive(:extract_and_merge_controller_data)
|
129
|
+
expect(exception_info).to_not receive(:customize_from_data_callback)
|
114
130
|
expected_data = {
|
115
131
|
"error_class" => "StandardError",
|
116
132
|
"error_string" => "StandardError: something went wrong",
|
@@ -122,12 +138,12 @@ module ExceptionHandling
|
|
122
138
|
}
|
123
139
|
}
|
124
140
|
|
125
|
-
|
141
|
+
expect(exception_info.data).to eq(expected_data)
|
126
142
|
end
|
127
143
|
end
|
128
144
|
|
129
145
|
context "enhanced_data" do
|
130
|
-
|
146
|
+
before do
|
131
147
|
@exception = StandardError.new("something went wrong")
|
132
148
|
@timestamp = Time.now
|
133
149
|
@exception_context = {
|
@@ -145,13 +161,13 @@ module ExceptionHandling
|
|
145
161
|
@data_callback = ->(data) { data[:custom_section] = "check this out" }
|
146
162
|
end
|
147
163
|
|
148
|
-
|
164
|
+
it "not return a mutable object for the session" do
|
149
165
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
150
166
|
exception_info.enhanced_data["session"]["hello"] = "world"
|
151
|
-
|
167
|
+
expect(@controller.session["hello"]).to be_nil
|
152
168
|
end
|
153
169
|
|
154
|
-
|
170
|
+
it "return a hash with generic exception attributes as well as context data" do
|
155
171
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
156
172
|
expected_data = {
|
157
173
|
"error_class" => "StandardError",
|
@@ -164,20 +180,20 @@ module ExceptionHandling
|
|
164
180
|
"location" => { "file" => "<no backtrace>", "line" => nil }
|
165
181
|
}
|
166
182
|
|
167
|
-
|
183
|
+
expect(prepare_data(exception_info.enhanced_data)).to eq(expected_data)
|
168
184
|
end
|
169
185
|
|
170
|
-
|
186
|
+
it "generate exception data appropriately if exception message is nil" do
|
171
187
|
exception_with_nil_message = RuntimeError.new(nil)
|
172
|
-
|
188
|
+
allow(exception_with_nil_message).to receive(:message).and_return(nil)
|
173
189
|
exception_info = ExceptionInfo.new(exception_with_nil_message, @exception_context, @timestamp)
|
174
190
|
exception_data = exception_info.enhanced_data
|
175
|
-
|
176
|
-
|
191
|
+
expect(exception_data["error_string"]).to eq("RuntimeError: ")
|
192
|
+
expect(exception_data["error"]).to eq("RuntimeError: ")
|
177
193
|
end
|
178
194
|
|
179
|
-
|
180
|
-
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, @controller)
|
195
|
+
it "include controller data when available" do
|
196
|
+
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: @controller)
|
181
197
|
expected_data = {
|
182
198
|
"error_class" => "StandardError",
|
183
199
|
"error_string" => "StandardError: something went wrong",
|
@@ -194,10 +210,10 @@ module ExceptionHandling
|
|
194
210
|
"location" => { "controller" => "dummy", "action" => "fail", "file" => "<no backtrace>", "line" => nil }
|
195
211
|
}
|
196
212
|
|
197
|
-
|
213
|
+
expect(prepare_data(exception_info.enhanced_data)).to eq(expected_data)
|
198
214
|
end
|
199
215
|
|
200
|
-
|
216
|
+
it "extract controller from rack specific exception context when not provided explicitly" do
|
201
217
|
@exception_context["action_controller.instance"] = @controller
|
202
218
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
203
219
|
expected_data = {
|
@@ -216,11 +232,11 @@ module ExceptionHandling
|
|
216
232
|
"location" => { "controller" => "dummy", "action" => "fail", "file" => "<no backtrace>", "line" => nil }
|
217
233
|
}
|
218
234
|
|
219
|
-
|
235
|
+
expect(prepare_data(exception_info.enhanced_data)).to eq(expected_data)
|
220
236
|
end
|
221
237
|
|
222
|
-
|
223
|
-
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, @controller)
|
238
|
+
it "add to_s attribute to specific sections that have their content in hash format" do
|
239
|
+
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: @controller)
|
224
240
|
expected_data = {
|
225
241
|
"error_class" => "StandardError",
|
226
242
|
"error_string" => "StandardError: something went wrong",
|
@@ -245,13 +261,13 @@ module ExceptionHandling
|
|
245
261
|
"location" => { "controller" => "dummy", "action" => "fail", "file" => "<no backtrace>", "line" => nil }
|
246
262
|
}
|
247
263
|
|
248
|
-
|
264
|
+
expect(exception_info.enhanced_data).to eq(expected_data)
|
249
265
|
end
|
250
266
|
|
251
|
-
|
267
|
+
it "filter out sensitive parameters like passwords" do
|
252
268
|
@controller.request.parameters[:password] = "super_secret"
|
253
269
|
@controller.request.parameters[:user] = { "password" => "also super secret", "password_confirmation" => "also super secret" }
|
254
|
-
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, @controller)
|
270
|
+
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: @controller)
|
255
271
|
expected_params = {
|
256
272
|
"password" => "[FILTERED]",
|
257
273
|
"advertiser_id" => 435, "controller" => "dummy",
|
@@ -261,11 +277,11 @@ module ExceptionHandling
|
|
261
277
|
"password_confirmation" => "[FILTERED]"
|
262
278
|
}
|
263
279
|
}
|
264
|
-
|
280
|
+
expect(exception_info.enhanced_data["request"]["params"]).to eq(expected_params)
|
265
281
|
end
|
266
282
|
|
267
|
-
|
268
|
-
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, nil, @data_callback)
|
283
|
+
it "include the changes from the custom data callback" do
|
284
|
+
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: nil, data_callback: @data_callback)
|
269
285
|
expected_data = {
|
270
286
|
"error_class" => "StandardError",
|
271
287
|
"error_string" => "StandardError: something went wrong",
|
@@ -278,11 +294,11 @@ module ExceptionHandling
|
|
278
294
|
"location" => { "file" => "<no backtrace>", "line" => nil }
|
279
295
|
}
|
280
296
|
|
281
|
-
|
297
|
+
expect(prepare_data(exception_info.enhanced_data)).to eq(expected_data)
|
282
298
|
end
|
283
299
|
|
284
|
-
|
285
|
-
|
300
|
+
it "apply the custom_data_hook results" do
|
301
|
+
allow(ExceptionHandling).to receive(:custom_data_hook).and_return(->(data) { data[:custom_hook] = "changes from custom hook" })
|
286
302
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
287
303
|
expected_data = {
|
288
304
|
"error_class" => "StandardError",
|
@@ -296,61 +312,61 @@ module ExceptionHandling
|
|
296
312
|
"location" => { "file" => "<no backtrace>", "line" => nil }
|
297
313
|
}
|
298
314
|
|
299
|
-
|
315
|
+
expect(prepare_data(exception_info.enhanced_data)).to eq(expected_data)
|
300
316
|
end
|
301
317
|
|
302
|
-
|
318
|
+
it "log info if the custom data hook results in a nil message exception" do
|
303
319
|
ExceptionHandling.custom_data_hook = ->(_data) do
|
304
320
|
raise_exception_with_nil_message
|
305
321
|
end
|
306
322
|
log_info_messages = []
|
307
|
-
|
323
|
+
allow(ExceptionHandling.logger).to receive(:info).with(any_args) do |message, _|
|
308
324
|
log_info_messages << message
|
309
325
|
end
|
310
326
|
|
311
327
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
312
328
|
exception_info.enhanced_data
|
313
|
-
|
329
|
+
expect(log_info_messages.find { |message| message =~ /Unable to execute custom custom_data_hook callback/ }).to be_truthy
|
314
330
|
ExceptionHandling.custom_data_hook = nil
|
315
331
|
end
|
316
332
|
end
|
317
333
|
|
318
334
|
context "exception_description" do
|
319
|
-
|
335
|
+
it "return the exception description from the global exception filter list" do
|
320
336
|
exception = StandardError.new("No route matches")
|
321
337
|
exception_info = ExceptionInfo.new(exception, {}, Time.now)
|
322
338
|
description = exception_info.exception_description
|
323
|
-
|
324
|
-
|
339
|
+
expect(description).to_not be_nil
|
340
|
+
expect(description.filter_name).to eq(:NoRoute)
|
325
341
|
end
|
326
342
|
|
327
|
-
|
343
|
+
it "find the description when filter criteria includes section in hash format" do
|
328
344
|
env = { server: "fe98" }
|
329
345
|
parameters = { advertiser_id: 435, controller: "sessions", action: "fail" }
|
330
346
|
session = { username: "jsmith", id: "session_key" }
|
331
347
|
request_uri = "host/path"
|
332
348
|
controller = create_dummy_controller(env, parameters, session, request_uri)
|
333
349
|
exception = StandardError.new("Request to click domain rejected")
|
334
|
-
exception_info = ExceptionInfo.new(exception,
|
335
|
-
|
350
|
+
exception_info = ExceptionInfo.new(exception, nil, Time.now, controller: controller)
|
351
|
+
expect(exception_info.enhanced_data[:request].is_a?(Hash)).to eq(true)
|
336
352
|
description = exception_info.exception_description
|
337
|
-
|
338
|
-
|
353
|
+
expect(description).to_not be_nil
|
354
|
+
expect(description.filter_name).to eq(:"Click Request Rejected")
|
339
355
|
end
|
340
356
|
|
341
|
-
|
357
|
+
it "return same description object for related errors (avoid reloading exception catalog from disk)" do
|
342
358
|
exception = StandardError.new("No route matches")
|
343
|
-
exception_info = ExceptionInfo.new(exception,
|
359
|
+
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
344
360
|
description = exception_info.exception_description
|
345
361
|
|
346
362
|
repeat_ex = StandardError.new("No route matches 2")
|
347
|
-
repeat_ex_info = ExceptionInfo.new(repeat_ex,
|
348
|
-
|
363
|
+
repeat_ex_info = ExceptionInfo.new(repeat_ex, nil, Time.now)
|
364
|
+
expect(repeat_ex_info.exception_description.object_id).to eq(description.object_id)
|
349
365
|
end
|
350
366
|
end
|
351
367
|
|
352
368
|
context "controller_name" do
|
353
|
-
|
369
|
+
before do
|
354
370
|
@exception = StandardError.new('something went wrong')
|
355
371
|
@timestamp = Time.now
|
356
372
|
@exception_context = {
|
@@ -362,73 +378,113 @@ module ExceptionHandling
|
|
362
378
|
}
|
363
379
|
end
|
364
380
|
|
365
|
-
|
381
|
+
it "returns honeybadger_grouping from the log context" do
|
382
|
+
allow(ExceptionHandling.logger).to receive(:current_context_for_thread).and_return({ honeybadger_grouping: 'Group 1' })
|
383
|
+
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
384
|
+
|
385
|
+
expect(exception_info.controller_name).to eq('Group 1')
|
386
|
+
end
|
387
|
+
|
388
|
+
it "returns honeybadger_grouping from log context even if controller is defined" do
|
389
|
+
allow(ExceptionHandling.logger).to receive(:current_context_for_thread).and_return({ honeybadger_grouping: 'Group 1' })
|
390
|
+
|
366
391
|
env = { server: 'fe98' }
|
367
392
|
parameters = { controller: 'some_controller' }
|
368
393
|
session = { username: 'smith' }
|
369
394
|
request_uri = "host/path"
|
370
395
|
controller = create_dummy_controller(env, parameters, session, request_uri)
|
371
|
-
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller)
|
396
|
+
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: controller)
|
372
397
|
|
373
|
-
|
398
|
+
expect(exception_info.controller_name).to eq('Group 1')
|
374
399
|
end
|
375
400
|
|
376
|
-
|
401
|
+
it "return controller_name when controller is present" do
|
402
|
+
env = { server: 'fe98' }
|
403
|
+
parameters = { controller: 'some_controller' }
|
404
|
+
session = { username: 'smith' }
|
405
|
+
request_uri = "host/path"
|
406
|
+
controller = create_dummy_controller(env, parameters, session, request_uri)
|
407
|
+
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: controller)
|
408
|
+
|
409
|
+
expect(exception_info.controller_name).to eq('some_controller')
|
410
|
+
end
|
411
|
+
|
412
|
+
it "return an empty string when controller is not present" do
|
377
413
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
378
414
|
|
379
|
-
|
415
|
+
expect(exception_info.controller_name).to eq('')
|
380
416
|
end
|
381
417
|
end
|
382
418
|
|
383
419
|
context "send_to_honeybadger?" do
|
384
|
-
|
385
|
-
|
420
|
+
it "be enabled when Honeybadger is defined and exception is not in the filter list" do
|
421
|
+
allow(ExceptionHandling).to receive(:honeybadger_defined?).and_return(true)
|
386
422
|
exception = StandardError.new("something went wrong")
|
387
|
-
exception_info = ExceptionInfo.new(exception,
|
388
|
-
|
389
|
-
|
423
|
+
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
424
|
+
expect(exception_info.exception_description).to be_nil
|
425
|
+
expect(exception_info.send_to_honeybadger?).to eq(true)
|
390
426
|
end
|
391
427
|
|
392
|
-
|
393
|
-
|
428
|
+
it "be enabled when Honeybadger is defined and exception is on the filter list with the flag turned on" do
|
429
|
+
allow(ExceptionHandling).to receive(:honeybadger_defined?).and_return(true)
|
394
430
|
exception = StandardError.new("No route matches")
|
395
|
-
exception_info = ExceptionInfo.new(exception,
|
396
|
-
|
397
|
-
|
398
|
-
|
431
|
+
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
432
|
+
expect(exception_info.exception_description).to_not be_nil
|
433
|
+
expect(exception_info.exception_description.send_to_honeybadger).to eq(true)
|
434
|
+
expect(exception_info.send_to_honeybadger?).to eq(true)
|
399
435
|
end
|
400
436
|
|
401
|
-
|
402
|
-
|
437
|
+
it "be disabled when Honeybadger is defined and exception is on the filter list with the flag turned off" do
|
438
|
+
allow(ExceptionHandling).to receive(:honeybadger_defined?).and_return(true)
|
403
439
|
exception = StandardError.new("No route matches")
|
404
|
-
exception_info = ExceptionInfo.new(exception,
|
405
|
-
|
406
|
-
|
407
|
-
|
440
|
+
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
441
|
+
expect(exception_info.exception_description).to_not be_nil
|
442
|
+
allow(exception_info.exception_description).to receive(:send_to_honeybadger).and_return(false)
|
443
|
+
expect(exception_info.send_to_honeybadger?).to eq(false)
|
408
444
|
end
|
409
445
|
|
410
|
-
|
411
|
-
|
446
|
+
it "be disabled when Honeybadger is not defined" do
|
447
|
+
allow(ExceptionHandling).to receive(:honeybadger_defined?).and_return(false)
|
412
448
|
exception = StandardError.new("something went wrong")
|
413
|
-
exception_info = ExceptionInfo.new(exception,
|
414
|
-
|
415
|
-
|
449
|
+
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
450
|
+
expect(exception_info.exception_description).to be_nil
|
451
|
+
expect(exception_info.send_to_honeybadger?).to eq(false)
|
416
452
|
end
|
417
453
|
end
|
418
454
|
|
419
455
|
context "honeybadger_context_data" do
|
420
|
-
|
456
|
+
before do
|
457
|
+
allow(ExceptionHandling.logger).to receive(:current_context_for_thread).and_return({ cuid: 'ABCD' })
|
458
|
+
end
|
459
|
+
|
460
|
+
it "include thread_context when log_context: is nil" do
|
461
|
+
exception_with_nil_message = RuntimeError.new(nil)
|
462
|
+
allow(exception_with_nil_message).to receive(:message).and_return(nil)
|
463
|
+
exception_info = ExceptionInfo.new(exception_with_nil_message, @exception_context, @timestamp)
|
464
|
+
honeybadger_context_data = exception_info.honeybadger_context_data
|
465
|
+
expect(honeybadger_context_data[:log_context]).to eq({ "cuid" => 'ABCD' })
|
466
|
+
end
|
467
|
+
|
468
|
+
it "include thread context merged with log_context:" do
|
469
|
+
exception_with_nil_message = RuntimeError.new(nil)
|
470
|
+
allow(exception_with_nil_message).to receive(:message).and_return(nil)
|
471
|
+
exception_info = ExceptionInfo.new(exception_with_nil_message, @exception_context, @timestamp, log_context: { url: 'http://example.com' })
|
472
|
+
honeybadger_context_data = exception_info.honeybadger_context_data
|
473
|
+
expect(honeybadger_context_data[:log_context]).to eq({ "cuid" => 'ABCD', "url" => 'http://example.com' })
|
474
|
+
end
|
475
|
+
|
476
|
+
it "return the error details and relevant context data to be used as honeybadger notification context while filtering sensitive data" do
|
421
477
|
env = { server: "fe98" }
|
422
478
|
parameters = { advertiser_id: 435 }
|
423
479
|
session = { username: "jsmith" }
|
424
480
|
request_uri = "host/path"
|
425
481
|
controller = create_dummy_controller(env, parameters, session, request_uri)
|
426
|
-
|
482
|
+
allow(ExceptionHandling).to receive(:server_name).and_return("invoca_fe98")
|
427
483
|
|
428
484
|
exception = StandardError.new("Some Exception")
|
429
485
|
exception.set_backtrace([
|
430
|
-
"
|
431
|
-
"
|
486
|
+
"spec/unit/exception_handling_test.rb:847:in `exception_1'",
|
487
|
+
"spec/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"
|
432
488
|
])
|
433
489
|
exception_context = { "SERVER_NAME" => "exceptional.com" }
|
434
490
|
data_callback = ->(data) do
|
@@ -438,7 +494,7 @@ module ExceptionHandling
|
|
438
494
|
data[:other_section] = "This should not be included in the response"
|
439
495
|
end
|
440
496
|
timestamp = Time.now
|
441
|
-
exception_info = ExceptionInfo.new(exception, exception_context, timestamp, controller, data_callback)
|
497
|
+
exception_info = ExceptionInfo.new(exception, exception_context, timestamp, controller: controller, data_callback: data_callback)
|
442
498
|
|
443
499
|
expected_data = {
|
444
500
|
timestamp: timestamp,
|
@@ -446,7 +502,6 @@ module ExceptionHandling
|
|
446
502
|
exception_context: { "SERVER_NAME" => "exceptional.com" },
|
447
503
|
server: "invoca_fe98",
|
448
504
|
scm_revision: "5b24eac37aaa91f5784901e9aabcead36fd9df82",
|
449
|
-
notes: "this is used by a test",
|
450
505
|
user_details: { "username" => "jsmith" },
|
451
506
|
request: {
|
452
507
|
"params" => { "advertiser_id" => 435 },
|
@@ -461,28 +516,30 @@ module ExceptionHandling
|
|
461
516
|
"SERVER_NAME" => "exceptional.com"
|
462
517
|
},
|
463
518
|
backtrace: [
|
464
|
-
"
|
465
|
-
"
|
519
|
+
"spec/unit/exception_handling_test.rb:847:in `exception_1'",
|
520
|
+
"spec/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"
|
466
521
|
],
|
467
|
-
event_response: "Event successfully received"
|
522
|
+
event_response: "Event successfully received",
|
523
|
+
log_context: { "cuid" => "ABCD" },
|
524
|
+
notes: "this is used by a test"
|
468
525
|
}
|
469
|
-
|
526
|
+
expect(exception_info.honeybadger_context_data).to eq(expected_data)
|
470
527
|
end
|
471
528
|
|
472
529
|
[['Hash', { 'cookie' => 'cookie_context' }],
|
473
530
|
['String', 'Entering Error State'],
|
474
531
|
['Array', ['Error1', 'Error2']]].each do |klass, value|
|
475
|
-
|
532
|
+
it "extract context from exception_context when it is a #{klass}" do
|
476
533
|
exception = StandardError.new("Exception")
|
477
534
|
exception_context = value
|
478
535
|
exception_info = ExceptionInfo.new(exception, exception_context, Time.now)
|
479
536
|
|
480
|
-
|
481
|
-
|
537
|
+
expect(value.class.name).to eq(klass)
|
538
|
+
expect(exception_info.honeybadger_context_data[:exception_context]).to eq(value)
|
482
539
|
end
|
483
540
|
end
|
484
541
|
|
485
|
-
|
542
|
+
it "filter out sensitive data from exception context such as [password, password_confirmation, oauth_token]" do
|
486
543
|
sensitive_data = {
|
487
544
|
"password" => "super_secret",
|
488
545
|
"password_confirmation" => "super_secret_confirmation",
|
@@ -517,15 +574,14 @@ module ExceptionHandling
|
|
517
574
|
}
|
518
575
|
}.merge(expected_sensitive_data)
|
519
576
|
|
520
|
-
|
577
|
+
expect(exception_info.honeybadger_context_data[:exception_context]).to eq(expected_exception_context)
|
521
578
|
end
|
522
579
|
|
523
|
-
|
580
|
+
it "omit context if exception_context is empty" do
|
524
581
|
exception = StandardError.new("Exception")
|
525
582
|
exception_context = ""
|
526
583
|
exception_info = ExceptionInfo.new(exception, exception_context, Time.now)
|
527
|
-
|
528
|
-
assert_nil exception_info.honeybadger_context_data[:exception_context]
|
584
|
+
expect(exception_info.honeybadger_context_data[:exception_context]).to be_nil
|
529
585
|
end
|
530
586
|
end
|
531
587
|
|