exception_handling 2.2.1 → 2.3.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +5 -0
  4. data/Gemfile +7 -6
  5. data/Gemfile.lock +26 -23
  6. data/README.md +0 -1
  7. data/Rakefile +4 -4
  8. data/config/exception_filters.yml +2 -3
  9. data/exception_handling.gemspec +12 -10
  10. data/lib/exception_handling/exception_catalog.rb +5 -4
  11. data/lib/exception_handling/exception_description.rb +28 -28
  12. data/lib/exception_handling/exception_info.rb +80 -72
  13. data/lib/exception_handling/honeybadger_callbacks.rb +41 -24
  14. data/lib/exception_handling/log_stub_error.rb +10 -8
  15. data/lib/exception_handling/mailer.rb +27 -48
  16. data/lib/exception_handling/methods.rb +15 -11
  17. data/lib/exception_handling/sensu.rb +7 -5
  18. data/lib/exception_handling/testing.rb +21 -19
  19. data/lib/exception_handling/version.rb +1 -1
  20. data/lib/exception_handling.rb +105 -200
  21. data/test/helpers/controller_helpers.rb +3 -1
  22. data/test/helpers/exception_helpers.rb +9 -0
  23. data/test/test_helper.rb +26 -21
  24. data/test/unit/exception_handling/exception_catalog_test.rb +15 -14
  25. data/test/unit/exception_handling/exception_description_test.rb +22 -31
  26. data/test/unit/exception_handling/exception_info_test.rb +76 -37
  27. data/test/unit/exception_handling/honeybadger_callbacks_test.rb +46 -9
  28. data/test/unit/exception_handling/log_error_stub_test.rb +6 -4
  29. data/test/unit/exception_handling/mailer_test.rb +8 -14
  30. data/test/unit/exception_handling/methods_test.rb +9 -6
  31. data/test/unit/exception_handling/sensu_test.rb +6 -4
  32. data/test/unit/exception_handling_test.rb +279 -364
  33. metadata +24 -24
  34. data/views/exception_handling/mailer/exception_notification.html.erb +0 -92
@@ -1,12 +1,14 @@
1
- require File.expand_path('../../../test_helper', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../../test_helper', __dir__)
2
4
 
3
5
  module ExceptionHandling
4
6
  class ExceptionCatalogTest < ActiveSupport::TestCase
5
7
 
6
8
  context "With stubbed yaml content" do
7
9
  setup do
8
- filter_list = { :exception1 => { error: "my error message" },
9
- :exception2 => { error: "some other message", session: "misc data" } }
10
+ filter_list = { exception1: { error: "my error message" },
11
+ exception2: { error: "some other message", session: "misc data" } }
10
12
  stub(YAML).load_file { filter_list }
11
13
 
12
14
  # bump modified time up to get the above filter loaded
@@ -16,7 +18,7 @@ module ExceptionHandling
16
18
  context "with loaded data" do
17
19
  setup do
18
20
  stub(File).mtime { incrementing_mtime }
19
- @exception_catalog = ExceptionCatalog.new( ExceptionHandling.filter_list_filename )
21
+ @exception_catalog = ExceptionCatalog.new(ExceptionHandling.filter_list_filename)
20
22
  @exception_catalog.send :load_file
21
23
  end
22
24
 
@@ -25,7 +27,7 @@ module ExceptionHandling
25
27
  end
26
28
 
27
29
  should "find messages in the catalog" do
28
- assert !@exception_catalog.find( error: "Scott says unlikely to ever match" )
30
+ assert !@exception_catalog.find(error: "Scott says unlikely to ever match")
29
31
  end
30
32
 
31
33
  should "find matching data" do
@@ -36,29 +38,28 @@ module ExceptionHandling
36
38
  end
37
39
 
38
40
  should "write errors loading the yaml file directly to the log file" do
39
- @exception_catalog = ExceptionCatalog.new( ExceptionHandling.filter_list_filename )
41
+ @exception_catalog = ExceptionCatalog.new(ExceptionHandling.filter_list_filename)
40
42
 
41
43
  mock(ExceptionHandling).log_error.never
42
- mock(ExceptionHandling).write_exception_to_log(anything(), "ExceptionCatalog#refresh_filters: ./config/exception_filters.yml", anything())
43
- mock(@exception_catalog).load_file { raise "noooooo"}
44
+ mock(ExceptionHandling).write_exception_to_log(anything, "ExceptionCatalog#refresh_filters: ./config/exception_filters.yml", anything)
45
+ mock(@exception_catalog).load_file { raise "noooooo" }
44
46
 
45
47
  @exception_catalog.find({})
46
48
  end
47
-
48
49
  end
49
50
 
50
51
  context "with live yaml content" do
51
52
  setup do
52
- @filename = File.expand_path('../../../../config/exception_filters.yml', __FILE__)
53
- @exception_catalog = ExceptionCatalog.new( @filename )
53
+ @filename = File.expand_path('../../../config/exception_filters.yml', __dir__)
54
+ @exception_catalog = ExceptionCatalog.new(@filename)
54
55
  assert_nothing_raised "Loading the exception filter should not raise" do
55
56
  @exception_catalog.send :load_file
56
57
  end
57
58
  end
58
59
 
59
60
  should "load the filter data" do
60
- assert !@exception_catalog.find( error: "Scott says unlikely to ever match" )
61
- assert !@exception_catalog.find( error: "Scott says unlikely to ever match" )
61
+ assert !@exception_catalog.find(error: "Scott says unlikely to ever match")
62
+ assert !@exception_catalog.find(error: "Scott says unlikely to ever match")
62
63
  end
63
64
  end
64
65
 
@@ -69,7 +70,7 @@ module ExceptionHandling
69
70
 
70
71
  should "not load filter data" do
71
72
  mock(ExceptionHandling).write_exception_to_log.with_any_args.never
72
- @exception_catalog.find( error: "Scott says unlikely to ever match" )
73
+ @exception_catalog.find(error: "Scott says unlikely to ever match")
73
74
  end
74
75
  end
75
76
 
@@ -1,23 +1,24 @@
1
- require File.expand_path('../../../test_helper', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../../test_helper', __dir__)
2
4
 
3
5
  module ExceptionHandling
4
6
  class ExceptionDescriptionTest < ActiveSupport::TestCase
5
7
 
6
8
  context "Filter" do
7
-
8
9
  should "allow direct matching of strings" do
9
- @f = ExceptionDescription.new(:filter1, :error => "my error message" )
10
- assert @f.match?( 'error' => "my error message")
10
+ @f = ExceptionDescription.new(:filter1, error: "my error message")
11
+ assert @f.match?('error' => "my error message")
11
12
  end
12
13
 
13
14
  should "allow direct matching of strings on with symbol keys" do
14
- @f = ExceptionDescription.new(:filter1, :error => "my error message" )
15
- assert @f.match?( :error => "my error message")
15
+ @f = ExceptionDescription.new(:filter1, error: "my error message")
16
+ assert @f.match?(error: "my error message")
16
17
  end
17
18
 
18
19
  should "allow wildcards to cross line boundries" do
19
- @f = ExceptionDescription.new(:filter1, :error => "my error message.*with multiple lines" )
20
- assert @f.match?( :error => "my error message\nwith more than one, with multiple lines")
20
+ @f = ExceptionDescription.new(:filter1, error: "my error message.*with multiple lines")
21
+ assert @f.match?(error: "my error message\nwith more than one, with multiple lines")
21
22
  end
22
23
 
23
24
  should "complain when no regexps have a value" do
@@ -28,12 +29,6 @@ module ExceptionHandling
28
29
  assert_raise(ArgumentError, "Unknown section: not_a_parameter") { ExceptionDescription.new(:filter1, error: "my error message", not_a_parameter: false) }
29
30
  end
30
31
 
31
- should "allow send email to be specified" do
32
- assert !ExceptionDescription.new(:filter1, error: "my error message", send_email: false ).send_email
33
- assert ExceptionDescription.new(:filter1, error: "my error message", send_email: true ).send_email
34
- assert !ExceptionDescription.new(:filter1, error: "my error message" ).send_email
35
- end
36
-
37
32
  should "allow send_to_honeybadger to be specified and have it disabled by default" do
38
33
  assert !ExceptionDescription.new(:filter1, error: "my error message", send_to_honeybadger: false).send_to_honeybadger
39
34
  assert ExceptionDescription.new(:filter1, error: "my error message", send_to_honeybadger: true).send_to_honeybadger
@@ -41,37 +36,35 @@ module ExceptionHandling
41
36
  end
42
37
 
43
38
  should "allow send_metric to be configured" do
44
- assert !ExceptionDescription.new(:filter1, error: "my error message", send_metric: false ).send_metric
45
- assert ExceptionDescription.new(:filter1, error: "my error message", send_email: true ).send_metric
46
- assert ExceptionDescription.new(:filter1, error: "my error message" ).send_metric
39
+ assert !ExceptionDescription.new(:filter1, error: "my error message", send_metric: false).send_metric
40
+ assert ExceptionDescription.new(:filter1, error: "my error message").send_metric
47
41
  end
48
42
 
49
43
  should "provide metric name" do
50
- assert_equal "filter1", ExceptionDescription.new(:filter1, error: "my error message" ).metric_name
51
- assert_equal "some_other_metric_name", ExceptionDescription.new(:filter1, error: "my error message", metric_name: :some_other_metric_name ).metric_name
44
+ assert_equal "filter1", ExceptionDescription.new(:filter1, error: "my error message").metric_name
45
+ assert_equal "some_other_metric_name", ExceptionDescription.new(:filter1, error: "my error message", metric_name: :some_other_metric_name).metric_name
52
46
  end
53
47
 
54
48
  should "replace spaces in metric name" do
55
- @f = ExceptionDescription.new(:"filter has spaces", :error => "my error message" )
49
+ @f = ExceptionDescription.new(:"filter has spaces", error: "my error message")
56
50
  assert_equal "filter_has_spaces", @f.metric_name
57
51
  end
58
52
 
59
53
  should "allow notes to be recorded" do
60
- assert_nil ExceptionDescription.new(:filter1, error: "my error message" ).notes
61
- assert_equal "a long string", ExceptionDescription.new(:filter1, error: "my error message", notes: "a long string" ).notes
54
+ assert_nil ExceptionDescription.new(:filter1, error: "my error message").notes
55
+ assert_equal "a long string", ExceptionDescription.new(:filter1, error: "my error message", notes: "a long string").notes
62
56
  end
63
57
 
64
58
  should "not consider config options in the filter set" do
65
- assert ExceptionDescription.new(:filter1, error: "my error message", send_email: false ).match?( :error => "my error message")
66
- assert ExceptionDescription.new(:filter1, error: "my error message", send_metric: false ).match?( :error => "my error message")
67
- assert ExceptionDescription.new(:filter1, error: "my error message", metric_name: "false" ).match?( :error => "my error message")
68
- assert ExceptionDescription.new(:filter1, error: "my error message", notes: "hey" ).match?( :error => "my error message")
59
+ assert ExceptionDescription.new(:filter1, error: "my error message", send_metric: false).match?(error: "my error message")
60
+ assert ExceptionDescription.new(:filter1, error: "my error message", metric_name: "false").match?(error: "my error message")
61
+ assert ExceptionDescription.new(:filter1, error: "my error message", notes: "hey").match?(error: "my error message")
69
62
  end
70
63
 
71
64
  should "provide exception details" do
72
- exception_description = ExceptionDescription.new(:filter1, error: "my error message", notes: "hey" )
65
+ exception_description = ExceptionDescription.new(:filter1, error: "my error message", notes: "hey")
73
66
 
74
- expected = {"send_metric" => true, "metric_name" => "filter1", "notes" => "hey"}
67
+ expected = { "send_metric" => true, "metric_name" => "filter1", "notes" => "hey" }
75
68
 
76
69
  assert_equal expected, exception_description.exception_data
77
70
  end
@@ -80,12 +73,10 @@ module ExceptionHandling
80
73
  mobi = "ExceptionHandling::Warning: LoginAttempt::IPAddressLocked: failed login for 'mcc@mobistreak.com'"
81
74
  credit = "ExceptionHandling::Warning: LoginAttempt::IPAddressLocked: failed login for 'damon@thecreditpros.com'"
82
75
 
83
- exception_description = ExceptionDescription.new(:filter1, error: "ExceptionHandling::Warning: LoginAttempt::IPAddressLocked: failed login for '(mcc\@mobistreak|damon\@thecreditpros).com'" )
76
+ exception_description = ExceptionDescription.new(:filter1, error: "ExceptionHandling::Warning: LoginAttempt::IPAddressLocked: failed login for '(mcc\@mobistreak|damon\@thecreditpros).com'")
84
77
  assert exception_description.match?(error: mobi), "does not match mobi"
85
78
  assert exception_description.match?(error: credit), "does not match credit"
86
79
  end
87
-
88
80
  end
89
-
90
81
  end
91
82
  end
@@ -1,4 +1,6 @@
1
- require File.expand_path('../../../test_helper', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../../test_helper', __dir__)
2
4
  require_test_helper 'controller_helpers'
3
5
  require_test_helper 'exception_helpers'
4
6
 
@@ -228,10 +230,12 @@ module ExceptionHandling
228
230
  "session" => {
229
231
  "key" => "session_key",
230
232
  "data" => { "username" => "jsmith", "id" => "session_key" },
231
- "to_s" => "data:\n id: session_key\n username: jsmith\nkey: session_key\n" },
233
+ "to_s" => "data:\n id: session_key\n username: jsmith\nkey: session_key\n"
234
+ },
232
235
  "environment" => {
233
236
  "SERVER_NAME" => "exceptional.com",
234
- "to_s" => "SERVER_NAME: exceptional.com\n" },
237
+ "to_s" => "SERVER_NAME: exceptional.com\n"
238
+ },
235
239
  "request" => {
236
240
  "params" => { "advertiser_id" => 435, "controller" => "dummy", "action" => "fail" },
237
241
  "rails_root" => "Rails.root not defined. Is this a test environment?",
@@ -249,11 +253,11 @@ module ExceptionHandling
249
253
  @controller.request.parameters[:user] = { "password" => "also super secret", "password_confirmation" => "also super secret" }
250
254
  exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, @controller)
251
255
  expected_params = {
252
- "password" => "[FILTERED]",
256
+ "password" => "[FILTERED]",
253
257
  "advertiser_id" => 435, "controller" => "dummy",
254
- "action" => "fail",
255
- "user" => {
256
- "password" => "[FILTERED]",
258
+ "action" => "fail",
259
+ "user" => {
260
+ "password" => "[FILTERED]",
257
261
  "password_confirmation" => "[FILTERED]"
258
262
  }
259
263
  }
@@ -296,7 +300,7 @@ module ExceptionHandling
296
300
  end
297
301
 
298
302
  should "log info if the custom data hook results in a nil message exception" do
299
- ExceptionHandling.custom_data_hook = lambda do |data|
303
+ ExceptionHandling.custom_data_hook = ->(_data) do
300
304
  raise_exception_with_nil_message
301
305
  end
302
306
  log_info_messages = []
@@ -345,9 +349,40 @@ module ExceptionHandling
345
349
  end
346
350
  end
347
351
 
352
+ context "controller_name" do
353
+ setup do
354
+ @exception = StandardError.new('something went wrong')
355
+ @timestamp = Time.now
356
+ @exception_context = {
357
+ 'rack.session' => {
358
+ user_id: 23,
359
+ user_name: 'John'
360
+ },
361
+ 'SERVER_NAME' => 'exceptional.com'
362
+ }
363
+ end
364
+
365
+ should "return controller_name when controller is present" do
366
+ env = { server: 'fe98' }
367
+ parameters = { controller: 'some_controller' }
368
+ session = { username: 'smith' }
369
+ request_uri = "host/path"
370
+ controller = create_dummy_controller(env, parameters, session, request_uri)
371
+ exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp, controller)
372
+
373
+ assert_equal 'some_controller', exception_info.controller_name
374
+ end
375
+
376
+ should "return an empty string when controller is not present" do
377
+ exception_info = ExceptionInfo.new(@exception, @exception_context, @timestamp)
378
+
379
+ assert_equal '', exception_info.controller_name
380
+ end
381
+ end
382
+
348
383
  context "send_to_honeybadger?" do
349
384
  should "be enabled when Honeybadger is defined and exception is not in the filter list" do
350
- stub(ExceptionHandling).honeybadger? { true }
385
+ stub(ExceptionHandling).honeybadger_defined? { true }
351
386
  exception = StandardError.new("something went wrong")
352
387
  exception_info = ExceptionInfo.new(exception, {}, Time.now)
353
388
  assert_nil exception_info.exception_description
@@ -355,7 +390,7 @@ module ExceptionHandling
355
390
  end
356
391
 
357
392
  should "be enabled when Honeybadger is defined and exception is on the filter list with the flag turned on" do
358
- stub(ExceptionHandling).honeybadger? { true }
393
+ stub(ExceptionHandling).honeybadger_defined? { true }
359
394
  exception = StandardError.new("No route matches")
360
395
  exception_info = ExceptionInfo.new(exception, {}, Time.now)
361
396
  assert_not_nil exception_info.exception_description
@@ -364,7 +399,7 @@ module ExceptionHandling
364
399
  end
365
400
 
366
401
  should "be disabled when Honeybadger is defined and exception is on the filter list with the flag turned off" do
367
- stub(ExceptionHandling).honeybadger? { true }
402
+ stub(ExceptionHandling).honeybadger_defined? { true }
368
403
  exception = StandardError.new("No route matches")
369
404
  exception_info = ExceptionInfo.new(exception, {}, Time.now)
370
405
  assert_not_nil exception_info.exception_description
@@ -373,7 +408,7 @@ module ExceptionHandling
373
408
  end
374
409
 
375
410
  should "be disabled when Honeybadger is not defined" do
376
- stub(ExceptionHandling).honeybadger? { false }
411
+ stub(ExceptionHandling).honeybadger_defined? { false }
377
412
  exception = StandardError.new("something went wrong")
378
413
  exception_info = ExceptionInfo.new(exception, {}, Time.now)
379
414
  assert_nil exception_info.exception_description
@@ -390,10 +425,11 @@ module ExceptionHandling
390
425
  controller = create_dummy_controller(env, parameters, session, request_uri)
391
426
  stub(ExceptionHandling).server_name { "invoca_fe98" }
392
427
 
393
- exception = StandardError.new("Some BS")
428
+ exception = StandardError.new("Some Exception")
394
429
  exception.set_backtrace([
395
- "test/unit/exception_handling_test.rb:847:in `exception_1'",
396
- "test/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"])
430
+ "test/unit/exception_handling_test.rb:847:in `exception_1'",
431
+ "test/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"
432
+ ])
397
433
  exception_context = { "SERVER_NAME" => "exceptional.com" }
398
434
  data_callback = ->(data) do
399
435
  data[:scm_revision] = "5b24eac37aaa91f5784901e9aabcead36fd9df82"
@@ -415,46 +451,49 @@ module ExceptionHandling
415
451
  request: {
416
452
  "params" => { "advertiser_id" => 435 },
417
453
  "rails_root" => "Rails.root not defined. Is this a test environment?",
418
- "url" => "host/path" },
454
+ "url" => "host/path"
455
+ },
419
456
  session: {
420
457
  "key" => nil,
421
- "data" => { "username" => "jsmith" } },
458
+ "data" => { "username" => "jsmith" }
459
+ },
422
460
  environment: {
423
- "SERVER_NAME" => "exceptional.com" },
461
+ "SERVER_NAME" => "exceptional.com"
462
+ },
424
463
  backtrace: [
425
464
  "test/unit/exception_handling_test.rb:847:in `exception_1'",
426
- "test/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"],
465
+ "test/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"
466
+ ],
427
467
  event_response: "Event successfully received"
428
468
  }
429
469
  assert_equal_with_diff expected_data, exception_info.honeybadger_context_data
430
470
  end
431
471
 
432
- [ ['Hash', { 'cookie' => 'cookie_context' } ],
433
- ['String', 'Entering Error State' ],
434
- ['Array', ['Error1', 'Error2'] ]].each do |klass, value|
435
-
436
- should "extract context from exception_context when it is a #{klass}" do
437
- exception = StandardError.new("Exception")
438
- exception_context = value
439
- exception_info = ExceptionInfo.new(exception, exception_context, Time.now)
472
+ [['Hash', { 'cookie' => 'cookie_context' }],
473
+ ['String', 'Entering Error State'],
474
+ ['Array', ['Error1', 'Error2']]].each do |klass, value|
475
+ should "extract context from exception_context when it is a #{klass}" do
476
+ exception = StandardError.new("Exception")
477
+ exception_context = value
478
+ exception_info = ExceptionInfo.new(exception, exception_context, Time.now)
440
479
 
441
- assert_equal klass, value.class.name
442
- assert_equal value, exception_info.honeybadger_context_data[:exception_context]
443
- end
480
+ assert_equal klass, value.class.name
481
+ assert_equal value, exception_info.honeybadger_context_data[:exception_context]
482
+ end
444
483
  end
445
484
 
446
485
  should "filter out sensitive data from exception context such as [password, password_confirmation, oauth_token]" do
447
486
  sensitive_data = {
448
- "password" => "super_secret",
487
+ "password" => "super_secret",
449
488
  "password_confirmation" => "super_secret_confirmation",
450
- "oauth_token" => "super_secret_oauth_token"
489
+ "oauth_token" => "super_secret_oauth_token"
451
490
  }
452
491
 
453
492
  exception = StandardError.new("boom")
454
493
  exception_context = {
455
494
  "SERVER_NAME" => "exceptional.com",
456
- "one_layer" => sensitive_data,
457
- "two_layers" => {
495
+ "one_layer" => sensitive_data,
496
+ "two_layers" => {
458
497
  "sensitive_data" => sensitive_data
459
498
  },
460
499
  "rack.request.form_vars" => "username=investor%40invoca.com&password=my_special_password&commit=Log+In",
@@ -468,8 +507,8 @@ module ExceptionHandling
468
507
  expected_sensitive_data = ["password", "password_confirmation", "oauth_token"].build_hash { |key| [key, "[FILTERED]"] }
469
508
  expected_exception_context = {
470
509
  "SERVER_NAME" => "exceptional.com",
471
- "one_layer" => expected_sensitive_data,
472
- "two_layers" => {
510
+ "one_layer" => expected_sensitive_data,
511
+ "two_layers" => {
473
512
  "sensitive_data" => expected_sensitive_data
474
513
  },
475
514
  "rack.request.form_vars" => "username=investor%40invoca.com&password=[FILTERED]&commit=Log+In",
@@ -491,7 +530,7 @@ module ExceptionHandling
491
530
  end
492
531
 
493
532
  def prepare_data(data)
494
- data.each do |key, section|
533
+ data.each do |_key, section|
495
534
  if section.is_a?(Hash)
496
535
  section.delete(:to_s)
497
536
  end
@@ -1,4 +1,6 @@
1
- require File.expand_path('../../../test_helper', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../../test_helper', __dir__)
2
4
 
3
5
  module ExceptionHandling
4
6
  class HoneybadgerCallbacksTest < ActiveSupport::TestCase
@@ -34,6 +36,24 @@ module ExceptionHandling
34
36
  end
35
37
  end
36
38
 
39
+ class TestRaiseOnInspect < TestPoroWithAttribute
40
+ def inspect
41
+ raise "some error"
42
+ end
43
+ end
44
+
45
+ class TestRaiseOnInspectWithId < TestRaiseOnInspect
46
+ def id
47
+ 123
48
+ end
49
+ end
50
+
51
+ class TestRaiseOnInspectWithToPk < TestRaiseOnInspect
52
+ def to_pk
53
+ "SomeRecord-123"
54
+ end
55
+ end
56
+
37
57
  context "register_callbacks" do
38
58
  should "store the callbacks in the honeybadger object" do
39
59
  HoneybadgerCallbacks.register_callbacks
@@ -46,37 +66,54 @@ module ExceptionHandling
46
66
  should "not inspect String, Hash, Array, Set, Numeric, TrueClass, FalseClass, NilClass" do
47
67
  [
48
68
  ['test', String],
49
- [{a: 1}, Hash],
50
- [[1,2], Array],
51
- [Set.new([1,2]), Set],
69
+ [{ a: 1 }, Hash],
70
+ [[1, 2], Array],
71
+ [Set.new([1, 2]), Set],
52
72
  [4.5, Numeric],
53
73
  [true, TrueClass],
54
74
  [false, FalseClass],
55
75
  [nil, NilClass]
56
76
  ].each do |object, expected_class|
57
- result = HoneybadgerCallbacks.local_variable_filter(:variable_name, object, [])
77
+ result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, object, [])
58
78
  assert result.is_a?(expected_class), "Expected #{expected_class.name} but got #{result.class.name}"
59
79
  end
60
80
  end
61
81
 
62
82
  should "inspect other classes" do
63
- result = HoneybadgerCallbacks.local_variable_filter(:variable_name, TestPoroWithAttribute.new, ['password'])
83
+ result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, TestPoroWithAttribute.new, ['password'])
64
84
  assert_match(/#<ExceptionHandling::HoneybadgerCallbacksTest::TestPoroWithAttribute:.* @test_attribute="test">/, result)
65
85
  end
66
86
 
87
+ context "when inspect raises exceptions" do
88
+ should "handle exceptions for objects" do
89
+ result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, TestRaiseOnInspect.new, ['password'])
90
+ assert_equal "#<ExceptionHandling::HoneybadgerCallbacksTest::TestRaiseOnInspect [error 'RuntimeError: some error' while calling #inspect]>", result
91
+ end
92
+
93
+ should "handle exceptions for objects responding to id" do
94
+ result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, TestRaiseOnInspectWithId.new, ['password'])
95
+ assert_equal "#<ExceptionHandling::HoneybadgerCallbacksTest::TestRaiseOnInspectWithId @id=123 [error 'RuntimeError: some error' while calling #inspect]>", result
96
+ end
97
+
98
+ should "handle exceptions for objects responding to to_pik" do
99
+ result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, TestRaiseOnInspectWithToPk.new, ['password'])
100
+ assert_equal "#<ExceptionHandling::HoneybadgerCallbacksTest::TestRaiseOnInspectWithToPk @pk=SomeRecord-123 [error 'RuntimeError: some error' while calling #inspect]>", result
101
+ end
102
+ end
103
+
67
104
  context "not inspect objects that contain filter keys" do
68
105
  should "use to_pk if available, even if id is available" do
69
- result = HoneybadgerCallbacks.local_variable_filter(:variable_name, TestPoroWithFilteredAttributePkAndId.new, ['password'])
106
+ result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, TestPoroWithFilteredAttributePkAndId.new, ['password'])
70
107
  assert_match(/#<ExceptionHandling::HoneybadgerCallbacksTest::TestPoroWithFilteredAttributePkAndId @pk=TestPoroWithFilteredAttributePkAndId_1, \[FILTERED\]>/, result)
71
108
  end
72
109
 
73
110
  should "use id if to_pk is not available" do
74
- result = HoneybadgerCallbacks.local_variable_filter(:variable_name, TestPoroWithFilteredAttributeAndId.new, ['password'])
111
+ result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, TestPoroWithFilteredAttributeAndId.new, ['password'])
75
112
  assert_match(/#<ExceptionHandling::HoneybadgerCallbacksTest::TestPoroWithFilteredAttributeAndId @id=1, \[FILTERED\]>/, result)
76
113
  end
77
114
 
78
115
  should "print the object name if no id or to_pk" do
79
- result = HoneybadgerCallbacks.local_variable_filter(:variable_name, TestPoroWithFilteredAttribute.new, ['password'])
116
+ result = HoneybadgerCallbacks.send(:local_variable_filter, :variable_name, TestPoroWithFilteredAttribute.new, ['password'])
80
117
  assert_match(/#<ExceptionHandling::HoneybadgerCallbacksTest::TestPoroWithFilteredAttribute \[FILTERED\]>/, result)
81
118
  end
82
119
  end
@@ -1,4 +1,6 @@
1
- require File.expand_path('../../../test_helper', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../../test_helper', __dir__)
2
4
 
3
5
  module ExceptionHandling
4
6
  class LogErrorStubTest < ActiveSupport::TestCase
@@ -18,7 +20,7 @@ module ExceptionHandling
18
20
  begin
19
21
  ExceptionHandling.log_error("Something happened")
20
22
  flunk
21
- rescue Exception => ex #LogErrorStub::UnexpectedExceptionLogged => ex
23
+ rescue Exception => ex # LogErrorStub::UnexpectedExceptionLogged => ex
22
24
  assert ex.to_s.starts_with?("StandardError: Something happened"), ex.to_s
23
25
  end
24
26
 
@@ -28,8 +30,8 @@ module ExceptionHandling
28
30
  rescue => ex
29
31
  begin
30
32
  ExceptionHandling.log_error(ex)
31
- rescue LogErrorStub::UnexpectedExceptionLogged => ex_inner
32
- assert ex_inner.to_s.starts_with?("RaisedError: This should raise"), ex_inner.to_s
33
+ rescue LogErrorStub::UnexpectedExceptionLogged => ex
34
+ assert ex.to_s.starts_with?("RaisedError: This should raise"), ex.to_s
33
35
  end
34
36
  end
35
37
  end
@@ -1,4 +1,6 @@
1
- require File.expand_path('../../../test_helper', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../../test_helper', __dir__)
2
4
 
3
5
  module ExceptionHandling
4
6
  class MailerTest < ActionMailer::TestCase
@@ -18,14 +20,6 @@ module ExceptionHandling
18
20
  ExceptionHandling.escalation_recipients = ['test_escalation@invoca.com']
19
21
  end
20
22
 
21
- should "deliver" do
22
- #ActionMailer::Base.delivery_method = :smtp
23
- result = ExceptionHandling::Mailer.exception_notification({ :error => "Test Error."}).deliver_now
24
- assert_match(/Test Error./, result.body.to_s)
25
- assert_equal_with_diff ['test_exception@invoca.com'], result.to
26
- assert_emails 1
27
- end
28
-
29
23
  context "log_parser_exception_notification" do
30
24
  should "send with string" do
31
25
  result = ExceptionHandling::Mailer.log_parser_exception_notification("This is my fake error", "My Fake Subj").deliver_now
@@ -46,7 +40,7 @@ module ExceptionHandling
46
40
  ExceptionHandling.email_environment = 'Staging Full'
47
41
  ExceptionHandling.server_name = 'test-fe3'
48
42
 
49
- ExceptionHandling::Mailer.escalation_notification("Your Favorite <b>Feature<b> Failed", :error_string => "It failed because of an error\n <i>More Info<i>", :timestamp => 1234567 ).deliver_now
43
+ ExceptionHandling::Mailer.escalation_notification("Your Favorite <b>Feature<b> Failed", error_string: "It failed because of an error\n <i>More Info<i>", timestamp: 1234567).deliver_now
50
44
 
51
45
  assert_emails 1
52
46
  result = ActionMailer::Base.deliveries.last
@@ -56,18 +50,18 @@ module ExceptionHandling
56
50
  assert_equal "Staging Full Escalation: Your Favorite <b>Feature<b> Failed", result.subject
57
51
  assert_select "title", "Exception Escalation"
58
52
  assert_select "html" do
59
- assert_select "body br", { :count => 4 }, result.body.to_s # plus 1 for the multiline summary
53
+ assert_select "body br", { count: 4 }, result.body.to_s # plus 1 for the multiline summary
60
54
  assert_select "body h3", "Your Favorite <b>Feature<b> Failed", result.body.to_s
61
55
  assert_select "body", /1234567/
62
56
  assert_select "body", /It failed because of an error/
63
57
  assert_select "body", /\n <i>More Info<i>/
64
58
  assert_select "body", /test-fe3/
65
- #assert_select "body", /#{Web::Application::GIT_REVISION}/
59
+ # assert_select "body", /#{Web::Application::GIT_REVISION}/
66
60
  end
67
61
  end
68
62
 
69
63
  should "use defaults for missing fields" do
70
- result = ExceptionHandling::Mailer.escalation_notification("Your Favorite Feature Failed", :error_string => "It failed because of an error\n More Info")
64
+ result = ExceptionHandling::Mailer.escalation_notification("Your Favorite Feature Failed", error_string: "It failed because of an error\n More Info")
71
65
  @body_html = Nokogiri::HTML(result.body.to_s)
72
66
 
73
67
  assert_equal_with_diff ['test_escalation@invoca.com'], result.to
@@ -93,7 +87,7 @@ module ExceptionHandling
93
87
  ExceptionHandling.production_support_recipients = recipients
94
88
  ExceptionHandling.last_exception_timestamp = Time.now.to_i
95
89
 
96
- mock(ExceptionHandling).escalate_custom(subject, exception, Time.now.to_i, recipients)
90
+ mock(ExceptionHandling).escalate(subject, exception, Time.now.to_i, recipients)
97
91
  ExceptionHandling.escalate_to_production_support(exception, subject)
98
92
  end
99
93
  end
@@ -1,9 +1,12 @@
1
- require File.expand_path('../../../test_helper', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../../test_helper', __dir__)
2
4
 
3
5
  require "exception_handling/testing"
4
6
 
5
7
  module ExceptionHandling
6
8
  class MethodsTest < ActiveSupport::TestCase
9
+ include ExceptionHelpers
7
10
 
8
11
  def dont_stub_log_error
9
12
  true
@@ -25,13 +28,13 @@ module ExceptionHandling
25
28
  end
26
29
 
27
30
  should "use the current_controller when available" do
28
- mock(Honeybadger).notify(anything)
31
+ capture_notifications
32
+
29
33
  mock(ExceptionHandling.logger).fatal(/blah/, anything)
30
34
  @controller.simulate_around_filter do
31
- ExceptionHandling.log_error( ArgumentError.new("blah") )
32
- mail = ActionMailer::Base.deliveries.last
33
- assert_match( @controller.request.request_uri, mail.body.to_s )
34
- # assert_match( Username.first.username.to_s, mail.body.to_s ) if defined?(Username)
35
+ ExceptionHandling.log_error(ArgumentError.new("blah"))
36
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect
37
+ assert_match(@controller.request.request_uri, sent_notifications.last.enhanced_data['request'].to_s)
35
38
  end
36
39
  end
37
40