exception_handling 2.6.1 → 2.7.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 +8 -24
- data/CHANGELOG.md +8 -1
- data/Gemfile +4 -4
- data/Gemfile.lock +19 -29
- data/Rakefile +6 -7
- data/lib/exception_handling/log_stub_error.rb +1 -2
- data/lib/exception_handling/logging_methods.rb +33 -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/lib/exception_handling.rb +2 -2
- data/{spec → test}/helpers/controller_helpers.rb +0 -0
- data/{spec → test}/helpers/exception_helpers.rb +2 -2
- data/{spec → test}/rake_test_warning_false.rb +0 -0
- data/{spec/spec_helper.rb → test/test_helper.rb} +39 -50
- data/test/unit/exception_handling/exception_catalog_test.rb +85 -0
- data/test/unit/exception_handling/exception_description_test.rb +82 -0
- data/{spec/unit/exception_handling/exception_info_spec.rb → test/unit/exception_handling/exception_info_test.rb} +107 -105
- data/{spec/unit/exception_handling/honeybadger_callbacks_spec.rb → test/unit/exception_handling/honeybadger_callbacks_test.rb} +20 -20
- data/{spec/unit/exception_handling/log_error_stub_spec.rb → test/unit/exception_handling/log_error_stub_test.rb} +22 -38
- data/test/unit/exception_handling/logging_methods_test.rb +37 -0
- data/{spec/unit/exception_handling/mailer_spec.rb → test/unit/exception_handling/mailer_test.rb} +17 -17
- data/test/unit/exception_handling/methods_test.rb +105 -0
- data/test/unit/exception_handling/sensu_test.rb +52 -0
- data/{spec/unit/exception_handling_spec.rb → test/unit/exception_handling_test.rb} +329 -325
- metadata +36 -34
- data/.rspec +0 -3
- data/spec/unit/exception_handling/exception_catalog_spec.rb +0 -85
- data/spec/unit/exception_handling/exception_description_spec.rb +0 -82
- data/spec/unit/exception_handling/methods_spec.rb +0 -84
- data/spec/unit/exception_handling/sensu_spec.rb +0 -51
@@ -1,58 +1,58 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require File.expand_path('../../
|
3
|
+
require File.expand_path('../../test_helper', __dir__)
|
4
4
|
require_test_helper 'controller_helpers'
|
5
5
|
require_test_helper 'exception_helpers'
|
6
6
|
|
7
7
|
module ExceptionHandling
|
8
|
-
|
8
|
+
class ExceptionInfoTest < ActiveSupport::TestCase
|
9
9
|
include ControllerHelpers
|
10
10
|
include ExceptionHelpers
|
11
11
|
|
12
12
|
context "initialize" do
|
13
|
-
|
13
|
+
setup 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
|
+
should "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
|
+
assert_equal @controller, exception_info.controller
|
26
26
|
end
|
27
27
|
|
28
|
-
|
28
|
+
should "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
|
+
assert_equal @controller, exception_info.controller
|
34
|
+
assert_not_equal exception_context["action_controller.instance"], exception_info.controller
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
should "leave controller unset when not included in the context hash" do
|
38
38
|
exception_info = ExceptionInfo.new(@exception, {}, @timestamp)
|
39
|
-
|
39
|
+
assert_nil exception_info.controller
|
40
40
|
end
|
41
41
|
|
42
|
-
|
42
|
+
should "leave controller unset when context is not in hash format" do
|
43
43
|
exception_info = ExceptionInfo.new(@exception, "string context", @timestamp)
|
44
|
-
|
44
|
+
assert_nil exception_info.controller
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
context "data" do
|
50
|
-
|
50
|
+
setup do
|
51
51
|
@exception = StandardError.new("something went wrong")
|
52
52
|
@timestamp = Time.now
|
53
53
|
end
|
54
54
|
|
55
|
-
|
55
|
+
should "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
|
+
assert_equal_with_diff expected_data, exception_info.data
|
77
77
|
end
|
78
78
|
|
79
|
-
|
79
|
+
should "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
|
+
assert_equal "RuntimeError: ", exception_data["error_string"]
|
83
|
+
assert_equal "RuntimeError: : custom context data", exception_data["error"]
|
84
84
|
end
|
85
85
|
|
86
|
-
|
86
|
+
should "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,10 +96,11 @@ module ExceptionHandling
|
|
96
96
|
"message" => "custom context data"
|
97
97
|
}
|
98
98
|
}
|
99
|
-
|
99
|
+
|
100
|
+
assert_equal_with_diff expected_data, exception_info.data
|
100
101
|
end
|
101
102
|
|
102
|
-
|
103
|
+
should "not include enhanced data from controller or custom data callback" do
|
103
104
|
env = { server: "fe98" }
|
104
105
|
parameters = { advertiser_id: 435 }
|
105
106
|
session = { username: "jsmith" }
|
@@ -108,8 +109,8 @@ module ExceptionHandling
|
|
108
109
|
data_callback = ->(data) { data[:custom_section] = "value" }
|
109
110
|
exception_info = ExceptionInfo.new(@exception, "custom context data", @timestamp, controller: controller, data_callback: data_callback)
|
110
111
|
|
111
|
-
|
112
|
-
|
112
|
+
dont_allow(exception_info).extract_and_merge_controller_data
|
113
|
+
dont_allow(exception_info).customize_from_data_callback
|
113
114
|
expected_data = {
|
114
115
|
"error_class" => "StandardError",
|
115
116
|
"error_string" => "StandardError: something went wrong",
|
@@ -121,12 +122,12 @@ module ExceptionHandling
|
|
121
122
|
}
|
122
123
|
}
|
123
124
|
|
124
|
-
|
125
|
+
assert_equal_with_diff expected_data, exception_info.data
|
125
126
|
end
|
126
127
|
end
|
127
128
|
|
128
129
|
context "enhanced_data" do
|
129
|
-
|
130
|
+
setup do
|
130
131
|
@exception = StandardError.new("something went wrong")
|
131
132
|
@timestamp = Time.now
|
132
133
|
@exception_context = {
|
@@ -144,13 +145,13 @@ module ExceptionHandling
|
|
144
145
|
@data_callback = ->(data) { data[:custom_section] = "check this out" }
|
145
146
|
end
|
146
147
|
|
147
|
-
|
148
|
+
should "not return a mutable object for the session" do
|
148
149
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
149
150
|
exception_info.enhanced_data["session"]["hello"] = "world"
|
150
|
-
|
151
|
+
assert_nil @controller.session["hello"]
|
151
152
|
end
|
152
153
|
|
153
|
-
|
154
|
+
should "return a hash with generic exception attributes as well as context data" do
|
154
155
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
155
156
|
expected_data = {
|
156
157
|
"error_class" => "StandardError",
|
@@ -163,19 +164,19 @@ module ExceptionHandling
|
|
163
164
|
"location" => { "file" => "<no backtrace>", "line" => nil }
|
164
165
|
}
|
165
166
|
|
166
|
-
|
167
|
+
assert_equal_with_diff expected_data, prepare_data(exception_info.enhanced_data)
|
167
168
|
end
|
168
169
|
|
169
|
-
|
170
|
+
should "generate exception data appropriately if exception message is nil" do
|
170
171
|
exception_with_nil_message = RuntimeError.new(nil)
|
171
|
-
|
172
|
+
stub(exception_with_nil_message).message { nil }
|
172
173
|
exception_info = ExceptionInfo.new(exception_with_nil_message, @exception_context, @timestamp)
|
173
174
|
exception_data = exception_info.enhanced_data
|
174
|
-
|
175
|
-
|
175
|
+
assert_equal "RuntimeError: ", exception_data["error_string"]
|
176
|
+
assert_equal "RuntimeError: ", exception_data["error"]
|
176
177
|
end
|
177
178
|
|
178
|
-
|
179
|
+
should "include controller data when available" do
|
179
180
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: @controller)
|
180
181
|
expected_data = {
|
181
182
|
"error_class" => "StandardError",
|
@@ -193,10 +194,10 @@ module ExceptionHandling
|
|
193
194
|
"location" => { "controller" => "dummy", "action" => "fail", "file" => "<no backtrace>", "line" => nil }
|
194
195
|
}
|
195
196
|
|
196
|
-
|
197
|
+
assert_equal_with_diff expected_data, prepare_data(exception_info.enhanced_data)
|
197
198
|
end
|
198
199
|
|
199
|
-
|
200
|
+
should "extract controller from rack specific exception context when not provided explicitly" do
|
200
201
|
@exception_context["action_controller.instance"] = @controller
|
201
202
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
202
203
|
expected_data = {
|
@@ -215,10 +216,10 @@ module ExceptionHandling
|
|
215
216
|
"location" => { "controller" => "dummy", "action" => "fail", "file" => "<no backtrace>", "line" => nil }
|
216
217
|
}
|
217
218
|
|
218
|
-
|
219
|
+
assert_equal_with_diff expected_data, prepare_data(exception_info.enhanced_data)
|
219
220
|
end
|
220
221
|
|
221
|
-
|
222
|
+
should "add to_s attribute to specific sections that have their content in hash format" do
|
222
223
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: @controller)
|
223
224
|
expected_data = {
|
224
225
|
"error_class" => "StandardError",
|
@@ -244,10 +245,10 @@ module ExceptionHandling
|
|
244
245
|
"location" => { "controller" => "dummy", "action" => "fail", "file" => "<no backtrace>", "line" => nil }
|
245
246
|
}
|
246
247
|
|
247
|
-
|
248
|
+
assert_equal_with_diff expected_data, exception_info.enhanced_data
|
248
249
|
end
|
249
250
|
|
250
|
-
|
251
|
+
should "filter out sensitive parameters like passwords" do
|
251
252
|
@controller.request.parameters[:password] = "super_secret"
|
252
253
|
@controller.request.parameters[:user] = { "password" => "also super secret", "password_confirmation" => "also super secret" }
|
253
254
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: @controller)
|
@@ -260,10 +261,10 @@ module ExceptionHandling
|
|
260
261
|
"password_confirmation" => "[FILTERED]"
|
261
262
|
}
|
262
263
|
}
|
263
|
-
|
264
|
+
assert_equal_with_diff expected_params, exception_info.enhanced_data["request"]["params"]
|
264
265
|
end
|
265
266
|
|
266
|
-
|
267
|
+
should "include the changes from the custom data callback" do
|
267
268
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: nil, data_callback: @data_callback)
|
268
269
|
expected_data = {
|
269
270
|
"error_class" => "StandardError",
|
@@ -277,11 +278,11 @@ module ExceptionHandling
|
|
277
278
|
"location" => { "file" => "<no backtrace>", "line" => nil }
|
278
279
|
}
|
279
280
|
|
280
|
-
|
281
|
+
assert_equal_with_diff expected_data, prepare_data(exception_info.enhanced_data)
|
281
282
|
end
|
282
283
|
|
283
|
-
|
284
|
-
|
284
|
+
should "apply the custom_data_hook results" do
|
285
|
+
stub(ExceptionHandling).custom_data_hook { ->(data) { data[:custom_hook] = "changes from custom hook" } }
|
285
286
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
286
287
|
expected_data = {
|
287
288
|
"error_class" => "StandardError",
|
@@ -295,35 +296,35 @@ module ExceptionHandling
|
|
295
296
|
"location" => { "file" => "<no backtrace>", "line" => nil }
|
296
297
|
}
|
297
298
|
|
298
|
-
|
299
|
+
assert_equal_with_diff expected_data, prepare_data(exception_info.enhanced_data)
|
299
300
|
end
|
300
301
|
|
301
|
-
|
302
|
+
should "log info if the custom data hook results in a nil message exception" do
|
302
303
|
ExceptionHandling.custom_data_hook = ->(_data) do
|
303
304
|
raise_exception_with_nil_message
|
304
305
|
end
|
305
306
|
log_info_messages = []
|
306
|
-
|
307
|
+
stub(ExceptionHandling.logger).info.with_any_args do |message, _|
|
307
308
|
log_info_messages << message
|
308
309
|
end
|
309
310
|
|
310
311
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
311
312
|
exception_info.enhanced_data
|
312
|
-
|
313
|
+
assert log_info_messages.find { |message| message =~ /Unable to execute custom custom_data_hook callback/ }
|
313
314
|
ExceptionHandling.custom_data_hook = nil
|
314
315
|
end
|
315
316
|
end
|
316
317
|
|
317
318
|
context "exception_description" do
|
318
|
-
|
319
|
+
should "return the exception description from the global exception filter list" do
|
319
320
|
exception = StandardError.new("No route matches")
|
320
321
|
exception_info = ExceptionInfo.new(exception, {}, Time.now)
|
321
322
|
description = exception_info.exception_description
|
322
|
-
|
323
|
-
|
323
|
+
assert_not_nil description
|
324
|
+
assert_equal :NoRoute, description.filter_name
|
324
325
|
end
|
325
326
|
|
326
|
-
|
327
|
+
should "find the description when filter criteria includes section in hash format" do
|
327
328
|
env = { server: "fe98" }
|
328
329
|
parameters = { advertiser_id: 435, controller: "sessions", action: "fail" }
|
329
330
|
session = { username: "jsmith", id: "session_key" }
|
@@ -331,25 +332,25 @@ module ExceptionHandling
|
|
331
332
|
controller = create_dummy_controller(env, parameters, session, request_uri)
|
332
333
|
exception = StandardError.new("Request to click domain rejected")
|
333
334
|
exception_info = ExceptionInfo.new(exception, nil, Time.now, controller: controller)
|
334
|
-
|
335
|
+
assert_equal true, exception_info.enhanced_data[:request].is_a?(Hash)
|
335
336
|
description = exception_info.exception_description
|
336
|
-
|
337
|
-
|
337
|
+
assert_not_nil description
|
338
|
+
assert_equal :"Click Request Rejected", description.filter_name
|
338
339
|
end
|
339
340
|
|
340
|
-
|
341
|
+
should "return same description object for related errors (avoid reloading exception catalog from disk)" do
|
341
342
|
exception = StandardError.new("No route matches")
|
342
343
|
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
343
344
|
description = exception_info.exception_description
|
344
345
|
|
345
346
|
repeat_ex = StandardError.new("No route matches 2")
|
346
347
|
repeat_ex_info = ExceptionInfo.new(repeat_ex, nil, Time.now)
|
347
|
-
|
348
|
+
assert_equal description.object_id, repeat_ex_info.exception_description.object_id
|
348
349
|
end
|
349
350
|
end
|
350
351
|
|
351
352
|
context "controller_name" do
|
352
|
-
|
353
|
+
setup do
|
353
354
|
@exception = StandardError.new('something went wrong')
|
354
355
|
@timestamp = Time.now
|
355
356
|
@exception_context = {
|
@@ -361,7 +362,7 @@ module ExceptionHandling
|
|
361
362
|
}
|
362
363
|
end
|
363
364
|
|
364
|
-
|
365
|
+
should "return controller_name when controller is present" do
|
365
366
|
env = { server: 'fe98' }
|
366
367
|
parameters = { controller: 'some_controller' }
|
367
368
|
session = { username: 'smith' }
|
@@ -369,85 +370,85 @@ module ExceptionHandling
|
|
369
370
|
controller = create_dummy_controller(env, parameters, session, request_uri)
|
370
371
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller: controller)
|
371
372
|
|
372
|
-
|
373
|
+
assert_equal 'some_controller', exception_info.controller_name
|
373
374
|
end
|
374
375
|
|
375
|
-
|
376
|
+
should "return an empty string when controller is not present" do
|
376
377
|
exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
|
377
378
|
|
378
|
-
|
379
|
+
assert_equal '', exception_info.controller_name
|
379
380
|
end
|
380
381
|
end
|
381
382
|
|
382
383
|
context "send_to_honeybadger?" do
|
383
|
-
|
384
|
-
|
384
|
+
should "be enabled when Honeybadger is defined and exception is not in the filter list" do
|
385
|
+
stub(ExceptionHandling).honeybadger_defined? { true }
|
385
386
|
exception = StandardError.new("something went wrong")
|
386
387
|
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
387
|
-
|
388
|
-
|
388
|
+
assert_nil exception_info.exception_description
|
389
|
+
assert_equal true, exception_info.send_to_honeybadger?
|
389
390
|
end
|
390
391
|
|
391
|
-
|
392
|
-
|
392
|
+
should "be enabled when Honeybadger is defined and exception is on the filter list with the flag turned on" do
|
393
|
+
stub(ExceptionHandling).honeybadger_defined? { true }
|
393
394
|
exception = StandardError.new("No route matches")
|
394
395
|
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
395
|
-
|
396
|
-
|
397
|
-
|
396
|
+
assert_not_nil exception_info.exception_description
|
397
|
+
assert_equal true, exception_info.exception_description.send_to_honeybadger
|
398
|
+
assert_equal true, exception_info.send_to_honeybadger?
|
398
399
|
end
|
399
400
|
|
400
|
-
|
401
|
-
|
401
|
+
should "be disabled when Honeybadger is defined and exception is on the filter list with the flag turned off" do
|
402
|
+
stub(ExceptionHandling).honeybadger_defined? { true }
|
402
403
|
exception = StandardError.new("No route matches")
|
403
404
|
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
404
|
-
|
405
|
-
|
406
|
-
|
405
|
+
assert_not_nil exception_info.exception_description
|
406
|
+
stub(exception_info.exception_description).send_to_honeybadger { false }
|
407
|
+
assert_equal false, exception_info.send_to_honeybadger?
|
407
408
|
end
|
408
409
|
|
409
|
-
|
410
|
-
|
410
|
+
should "be disabled when Honeybadger is not defined" do
|
411
|
+
stub(ExceptionHandling).honeybadger_defined? { false }
|
411
412
|
exception = StandardError.new("something went wrong")
|
412
413
|
exception_info = ExceptionInfo.new(exception, nil, Time.now)
|
413
|
-
|
414
|
-
|
414
|
+
assert_nil exception_info.exception_description
|
415
|
+
assert_equal false, exception_info.send_to_honeybadger?
|
415
416
|
end
|
416
417
|
end
|
417
418
|
|
418
419
|
context "honeybadger_context_data" do
|
419
|
-
|
420
|
-
|
420
|
+
setup do
|
421
|
+
stub(ExceptionHandling.logger).current_context_for_thread { { cuid: 'ABCD' } }
|
421
422
|
end
|
422
423
|
|
423
|
-
|
424
|
+
should "include thread_context when log_context: is nil" do
|
424
425
|
exception_with_nil_message = RuntimeError.new(nil)
|
425
|
-
|
426
|
+
stub(exception_with_nil_message).message { nil }
|
426
427
|
exception_info = ExceptionInfo.new(exception_with_nil_message, @exception_context, @timestamp)
|
427
428
|
honeybadger_context_data = exception_info.honeybadger_context_data
|
428
|
-
|
429
|
+
assert_equal({ "cuid" => 'ABCD' }, honeybadger_context_data[:log_context])
|
429
430
|
end
|
430
431
|
|
431
|
-
|
432
|
+
should "include thread context merged with log_context:" do
|
432
433
|
exception_with_nil_message = RuntimeError.new(nil)
|
433
|
-
|
434
|
+
stub(exception_with_nil_message).message { nil }
|
434
435
|
exception_info = ExceptionInfo.new(exception_with_nil_message, @exception_context, @timestamp, log_context: { url: 'http://example.com' })
|
435
436
|
honeybadger_context_data = exception_info.honeybadger_context_data
|
436
|
-
|
437
|
+
assert_equal({ "cuid" => 'ABCD', "url" => 'http://example.com' }, honeybadger_context_data[:log_context])
|
437
438
|
end
|
438
439
|
|
439
|
-
|
440
|
+
should "return the error details and relevant context data to be used as honeybadger notification context while filtering sensitive data" do
|
440
441
|
env = { server: "fe98" }
|
441
442
|
parameters = { advertiser_id: 435 }
|
442
443
|
session = { username: "jsmith" }
|
443
444
|
request_uri = "host/path"
|
444
445
|
controller = create_dummy_controller(env, parameters, session, request_uri)
|
445
|
-
|
446
|
+
stub(ExceptionHandling).server_name { "invoca_fe98" }
|
446
447
|
|
447
448
|
exception = StandardError.new("Some Exception")
|
448
449
|
exception.set_backtrace([
|
449
|
-
"
|
450
|
-
"
|
450
|
+
"test/unit/exception_handling_test.rb:847:in `exception_1'",
|
451
|
+
"test/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"
|
451
452
|
])
|
452
453
|
exception_context = { "SERVER_NAME" => "exceptional.com" }
|
453
454
|
data_callback = ->(data) do
|
@@ -465,6 +466,7 @@ module ExceptionHandling
|
|
465
466
|
exception_context: { "SERVER_NAME" => "exceptional.com" },
|
466
467
|
server: "invoca_fe98",
|
467
468
|
scm_revision: "5b24eac37aaa91f5784901e9aabcead36fd9df82",
|
469
|
+
notes: "this is used by a test",
|
468
470
|
user_details: { "username" => "jsmith" },
|
469
471
|
request: {
|
470
472
|
"params" => { "advertiser_id" => 435 },
|
@@ -479,30 +481,29 @@ module ExceptionHandling
|
|
479
481
|
"SERVER_NAME" => "exceptional.com"
|
480
482
|
},
|
481
483
|
backtrace: [
|
482
|
-
"
|
483
|
-
"
|
484
|
+
"test/unit/exception_handling_test.rb:847:in `exception_1'",
|
485
|
+
"test/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"
|
484
486
|
],
|
485
487
|
event_response: "Event successfully received",
|
486
|
-
log_context: { "cuid" => "ABCD" }
|
487
|
-
notes: "this is used by a test"
|
488
|
+
log_context: { "cuid" => "ABCD" }
|
488
489
|
}
|
489
|
-
|
490
|
+
assert_equal_with_diff expected_data, exception_info.honeybadger_context_data
|
490
491
|
end
|
491
492
|
|
492
493
|
[['Hash', { 'cookie' => 'cookie_context' }],
|
493
494
|
['String', 'Entering Error State'],
|
494
495
|
['Array', ['Error1', 'Error2']]].each do |klass, value|
|
495
|
-
|
496
|
+
should "extract context from exception_context when it is a #{klass}" do
|
496
497
|
exception = StandardError.new("Exception")
|
497
498
|
exception_context = value
|
498
499
|
exception_info = ExceptionInfo.new(exception, exception_context, Time.now)
|
499
500
|
|
500
|
-
|
501
|
-
|
501
|
+
assert_equal klass, value.class.name
|
502
|
+
assert_equal value, exception_info.honeybadger_context_data[:exception_context]
|
502
503
|
end
|
503
504
|
end
|
504
505
|
|
505
|
-
|
506
|
+
should "filter out sensitive data from exception context such as [password, password_confirmation, oauth_token]" do
|
506
507
|
sensitive_data = {
|
507
508
|
"password" => "super_secret",
|
508
509
|
"password_confirmation" => "super_secret_confirmation",
|
@@ -537,14 +538,15 @@ module ExceptionHandling
|
|
537
538
|
}
|
538
539
|
}.merge(expected_sensitive_data)
|
539
540
|
|
540
|
-
|
541
|
+
assert_equal_with_diff expected_exception_context, exception_info.honeybadger_context_data[:exception_context]
|
541
542
|
end
|
542
543
|
|
543
|
-
|
544
|
+
should "omit context if exception_context is empty" do
|
544
545
|
exception = StandardError.new("Exception")
|
545
546
|
exception_context = ""
|
546
547
|
exception_info = ExceptionInfo.new(exception, exception_context, Time.now)
|
547
|
-
|
548
|
+
|
549
|
+
assert_nil exception_info.honeybadger_context_data[:exception_context]
|
548
550
|
end
|
549
551
|
end
|
550
552
|
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require File.expand_path('../../
|
3
|
+
require File.expand_path('../../test_helper', __dir__)
|
4
4
|
|
5
5
|
module ExceptionHandling
|
6
|
-
|
6
|
+
class HoneybadgerCallbacksTest < ActiveSupport::TestCase
|
7
7
|
|
8
8
|
class TestPoroWithAttribute
|
9
9
|
attr_reader :test_attribute
|
@@ -55,15 +55,15 @@ module ExceptionHandling
|
|
55
55
|
end
|
56
56
|
|
57
57
|
context "register_callbacks" do
|
58
|
-
|
58
|
+
should "store the callbacks in the honeybadger object" do
|
59
59
|
HoneybadgerCallbacks.register_callbacks
|
60
60
|
result = Honeybadger.config.local_variable_filter.call(:variable_name, 'test', [])
|
61
|
-
|
61
|
+
assert_equal('test', result)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
65
|
context "local_variable_filter" do
|
66
|
-
|
66
|
+
should "not inspect String, Hash, Array, Set, Numeric, TrueClass, FalseClass, NilClass" do
|
67
67
|
[
|
68
68
|
['test', String],
|
69
69
|
[{ a: 1 }, Hash],
|
@@ -75,46 +75,46 @@ module ExceptionHandling
|
|
75
75
|
[nil, NilClass]
|
76
76
|
].each do |object, expected_class|
|
77
77
|
result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, object, [])
|
78
|
-
|
78
|
+
assert result.is_a?(expected_class), "Expected #{expected_class.name} but got #{result.class.name}"
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
|
82
|
+
should "inspect other classes" do
|
83
83
|
result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, TestPoroWithAttribute.new, ['password'])
|
84
|
-
|
84
|
+
assert_match(/#<ExceptionHandling::HoneybadgerCallbacksTest::TestPoroWithAttribute:.* @test_attribute="test">/, result)
|
85
85
|
end
|
86
86
|
|
87
87
|
context "when inspect raises exceptions" do
|
88
|
-
|
88
|
+
should "handle exceptions for objects" do
|
89
89
|
result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, TestRaiseOnInspect.new, ['password'])
|
90
|
-
|
90
|
+
assert_equal "#<ExceptionHandling::HoneybadgerCallbacksTest::TestRaiseOnInspect [error 'RuntimeError: some error' while calling #inspect]>", result
|
91
91
|
end
|
92
92
|
|
93
|
-
|
93
|
+
should "handle exceptions for objects responding to id" do
|
94
94
|
result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, TestRaiseOnInspectWithId.new, ['password'])
|
95
|
-
|
95
|
+
assert_equal "#<ExceptionHandling::HoneybadgerCallbacksTest::TestRaiseOnInspectWithId @id=123 [error 'RuntimeError: some error' while calling #inspect]>", result
|
96
96
|
end
|
97
97
|
|
98
|
-
|
98
|
+
should "handle exceptions for objects responding to to_pk" do
|
99
99
|
result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, TestRaiseOnInspectWithToPk.new, ['password'])
|
100
|
-
|
100
|
+
assert_equal "#<ExceptionHandling::HoneybadgerCallbacksTest::TestRaiseOnInspectWithToPk @pk=SomeRecord-123 [error 'RuntimeError: some error' while calling #inspect]>", result
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
104
|
context "not inspect objects that contain filter keys" do
|
105
|
-
|
105
|
+
should "use to_pk if available, even if id is available" do
|
106
106
|
result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, TestPoroWithFilteredAttributePkAndId.new, ['password'])
|
107
|
-
|
107
|
+
assert_match(/#<ExceptionHandling::HoneybadgerCallbacksTest::TestPoroWithFilteredAttributePkAndId @pk=TestPoroWithFilteredAttributePkAndId_1, \[FILTERED\]>/, result)
|
108
108
|
end
|
109
109
|
|
110
|
-
|
110
|
+
should "use id if to_pk is not available" do
|
111
111
|
result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, TestPoroWithFilteredAttributeAndId.new, ['password'])
|
112
|
-
|
112
|
+
assert_match(/#<ExceptionHandling::HoneybadgerCallbacksTest::TestPoroWithFilteredAttributeAndId @id=1, \[FILTERED\]>/, result)
|
113
113
|
end
|
114
114
|
|
115
|
-
|
115
|
+
should "print the object name if no id or to_pk" do
|
116
116
|
result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, TestPoroWithFilteredAttribute.new, ['password'])
|
117
|
-
|
117
|
+
assert_match(/#<ExceptionHandling::HoneybadgerCallbacksTest::TestPoroWithFilteredAttribute \[FILTERED\]>/, result)
|
118
118
|
end
|
119
119
|
end
|
120
120
|
end
|