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,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
 
@@ -18,26 +20,26 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
18
20
  # don't let these out!
19
21
  end
20
22
 
21
- def custom_data_callback_returns_nil_message_exception(data)
23
+ def custom_data_callback_returns_nil_message_exception(_data)
22
24
  raise_exception_with_nil_message
23
25
  end
24
26
 
25
- def log_error_callback(data, ex, treat_like_warning, honeybadger_status)
27
+ def log_error_callback(_data, _ex, _treat_like_warning, _honeybadger_status)
26
28
  @fail_count += 1
27
29
  end
28
30
 
29
- def log_error_callback_config(data, ex, treat_like_warning, honeybadger_status)
31
+ def log_error_callback_config(data, _ex, treat_like_warning, honeybadger_status)
30
32
  @callback_data = data
31
33
  @treat_like_warning = treat_like_warning
32
34
  @fail_count += 1
33
35
  @honeybadger_status = honeybadger_status
34
36
  end
35
37
 
36
- def log_error_callback_with_failure(data, ex)
38
+ def log_error_callback_with_failure(_data, _ex)
37
39
  raise "this should be rescued"
38
40
  end
39
41
 
40
- def log_error_callback_returns_nil_message_exception(data, ex)
42
+ def log_error_callback_returns_nil_message_exception(_data, _ex)
41
43
  raise_exception_with_nil_message
42
44
  end
43
45
 
@@ -56,7 +58,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
56
58
  attr_accessor :callback_block
57
59
  attr_accessor :errback_block
58
60
 
59
- def resolve(hostname)
61
+ def resolve(_hostname)
60
62
  self
61
63
  end
62
64
 
@@ -101,31 +103,18 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
101
103
  class SmtpClientErrbackStub < SmtpClientStub
102
104
  end
103
105
 
104
- context "with honeybadger notify stubbed" do
106
+ context "with warn and honeybadger notify stubbed" do
105
107
  setup do
108
+ stub(ExceptionHandling).warn(anything)
106
109
  stub(Honeybadger).notify(anything)
107
110
  end
108
111
 
109
112
  context "#log_error" do
110
- setup do
111
- ExceptionHandling.mailer_send_enabled = true
112
- end
113
-
114
- should "take in additional key word args as logging context and pass them to the logger" do
113
+ should "take in additional keyword args as logging context and pass them to the logger" do
115
114
  ExceptionHandling.log_error('This is an Error', 'This is the prefix context', service_name: 'exception_handling')
116
115
  assert_match(/This is an Error/, logged_excluding_reload_filter.last[:message])
117
116
  assert_not_empty logged_excluding_reload_filter.last[:context]
118
- assert_equal logged_excluding_reload_filter.last[:context], { service_name: 'exception_handling' }
119
- end
120
-
121
- should "log the info and not raise another exception when sending email fails" do
122
- 9.times { ExceptionHandling.log_error('SomeError', 'Error Context') }
123
- mock(ExceptionHandling::Mailer).exception_notification(anything, anything, anything) { raise 'An Error' }
124
- mock(ExceptionHandling.logger) do |logger|
125
- logger.info(/ExceptionHandling.log_error_email rescued exception while logging StandardError: SomeError/, anything)
126
- end
127
- stub($stderr).puts
128
- ExceptionHandling.log_error('SomeError', 'Error Context')
117
+ assert_equal logged_excluding_reload_filter.last[:context], service_name: 'exception_handling'
129
118
  end
130
119
  end
131
120
 
@@ -141,7 +130,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
141
130
  ExceptionHandling.log_warning('This is a Warning', service_name: 'exception_handling')
142
131
  assert_match(/This is a Warning/, logged_excluding_reload_filter.last[:message])
143
132
  assert_not_empty logged_excluding_reload_filter.last[:context]
144
- assert_equal logged_excluding_reload_filter.last[:context], { service_name: 'exception_handling' }
133
+ assert_equal logged_excluding_reload_filter.last[:context], service_name: 'exception_handling'
145
134
  end
146
135
  end
147
136
 
@@ -150,7 +139,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
150
139
  ExceptionHandling.log_warning('This is an Info', service_name: 'exception_handling')
151
140
  assert_match(/This is an Info/, logged_excluding_reload_filter.last[:message])
152
141
  assert_not_empty logged_excluding_reload_filter.last[:context]
153
- assert_equal logged_excluding_reload_filter.last[:context], { service_name: 'exception_handling' }
142
+ assert_equal logged_excluding_reload_filter.last[:context], service_name: 'exception_handling'
154
143
  end
155
144
  end
156
145
 
@@ -159,48 +148,60 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
159
148
  ExceptionHandling.log_warning('This is a Debug', service_name: 'exception_handling')
160
149
  assert_match(/This is a Debug/, logged_excluding_reload_filter.last[:message])
161
150
  assert_not_empty logged_excluding_reload_filter.last[:context]
162
- assert_equal logged_excluding_reload_filter.last[:context], { service_name: 'exception_handling' }
151
+ assert_equal logged_excluding_reload_filter.last[:context], service_name: 'exception_handling'
163
152
  end
164
153
  end
165
154
 
166
- context "configuration" do
155
+ context "configuration with custom_data_hook or post_log_error_hook" do
156
+ teardown do
157
+ ExceptionHandling.custom_data_hook = nil
158
+ ExceptionHandling.post_log_error_hook = nil
159
+ end
160
+
167
161
  should "support a custom_data_hook" do
162
+ capture_notifications
163
+
168
164
  ExceptionHandling.custom_data_hook = method(:append_organization_info_config)
169
- ExceptionHandling.ensure_safe("mooo") { raise "Some BS" }
170
- assert_match(/Invoca Engineering Dept./, ActionMailer::Base.deliveries[-1].body.to_s)
171
- ExceptionHandling.custom_data_hook = nil
165
+ ExceptionHandling.ensure_safe("context") { raise "Some Exception" }
166
+
167
+ assert_match(/Invoca Engineering Dept./, sent_notifications.last.enhanced_data['user_details'].to_s)
172
168
  end
173
169
 
174
- should "support a log_error hook, and pass exception data, treat like warning, and logged_to_honeybadger to it" do
175
- begin
176
- @fail_count = 0
177
- @honeybadger_status = nil
178
- ExceptionHandling.post_log_error_hook = method(:log_error_callback_config)
179
- mock(Honeybadger).notify.with_any_args { '06220c5a-b471-41e5-baeb-de247da45a56' }
180
- ExceptionHandling.ensure_safe("mooo") { raise "Some BS" }
181
- assert_equal 1, @fail_count
182
- assert_equal false, @treat_like_warning
183
- assert_equal :success, @honeybadger_status
184
- ensure
185
- ExceptionHandling.post_log_error_hook = nil
186
- end
170
+ should "support a log_error hook, and pass exception_data, treat_like_warning, and logged_to_honeybadger to it" do
171
+ @fail_count = 0
172
+ @honeybadger_status = nil
173
+ ExceptionHandling.post_log_error_hook = method(:log_error_callback_config)
174
+
175
+ notify_args = []
176
+ mock(Honeybadger).notify.with_any_args { |info| notify_args << info; '06220c5a-b471-41e5-baeb-de247da45a56' }
177
+ ExceptionHandling.ensure_safe("context") { raise "Some Exception" }
178
+ assert_equal 1, @fail_count
179
+ assert_equal false, @treat_like_warning
180
+ assert_equal :success, @honeybadger_status
187
181
 
188
182
  assert_equal "this is used by a test", @callback_data["notes"]
189
- assert_match(/this is used by a test/, ActionMailer::Base.deliveries[-1].body.to_s)
183
+ assert_equal 1, notify_args.size, notify_args.inspect
184
+ assert_match(/this is used by a test/, notify_args.last[:context].to_s)
190
185
  end
191
186
 
192
- should "plumb treat like warning and logged_to_honeybadger to log error hook" do
193
- begin
194
- @fail_count = 0
195
- @honeybadger_status = nil
196
- ExceptionHandling.post_log_error_hook = method(:log_error_callback_config)
197
- ExceptionHandling.log_error(StandardError.new("Some BS"), "mooo", treat_like_warning: true)
198
- assert_equal 1, @fail_count
199
- assert_equal true, @treat_like_warning
200
- assert_equal :skipped, @honeybadger_status
201
- ensure
202
- ExceptionHandling.post_log_error_hook = nil
203
- end
187
+ should "plumb treat_like_warning and logged_to_honeybadger to log error hook" do
188
+ @fail_count = 0
189
+ @honeybadger_status = nil
190
+ ExceptionHandling.post_log_error_hook = method(:log_error_callback_config)
191
+ ExceptionHandling.log_error(StandardError.new("Some Exception"), "mooo", treat_like_warning: true)
192
+ assert_equal 1, @fail_count
193
+ assert_equal true, @treat_like_warning
194
+ assert_equal :skipped, @honeybadger_status
195
+ end
196
+
197
+ should "include logging context in the exception data" do
198
+ ExceptionHandling.post_log_error_hook = method(:log_error_callback_config)
199
+ ExceptionHandling.log_error(StandardError.new("Some Exception"), "mooo", nil, treat_like_warning: true, log_context_test: "contextual_logging")
200
+
201
+ expected_log_context = {
202
+ "log_context_test" => "contextual_logging"
203
+ }
204
+ assert_equal expected_log_context, @callback_data[:log_context]
204
205
  end
205
206
 
206
207
  should "support rescue exceptions from a log_error hook" do
@@ -209,9 +210,8 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
209
210
  stub(ExceptionHandling.logger).info.with_any_args do |message, _|
210
211
  log_info_messages << message
211
212
  end
212
- assert_nothing_raised { ExceptionHandling.ensure_safe("mooo") { raise "Some BS" } }
213
+ assert_nothing_raised { ExceptionHandling.ensure_safe("mooo") { raise "Some Exception" } }
213
214
  assert log_info_messages.find { |message| message =~ /Unable to execute custom log_error callback/ }
214
- ExceptionHandling.post_log_error_hook = nil
215
215
  end
216
216
 
217
217
  should "handle nil message exceptions resulting from the log_error hook" do
@@ -220,9 +220,8 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
220
220
  stub(ExceptionHandling.logger).info.with_any_args do |message, _|
221
221
  log_info_messages << message
222
222
  end
223
- assert_nothing_raised { ExceptionHandling.ensure_safe("mooo") { raise "Some BS" } }
223
+ assert_nothing_raised { ExceptionHandling.ensure_safe("mooo") { raise "Some Exception" } }
224
224
  assert log_info_messages.find { |message| message =~ /Unable to execute custom log_error callback/ }
225
- ExceptionHandling.post_log_error_hook = nil
226
225
  end
227
226
 
228
227
  should "handle nil message exceptions resulting from the custom data hook" do
@@ -231,20 +230,13 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
231
230
  stub(ExceptionHandling.logger).info.with_any_args do |message, _|
232
231
  log_info_messages << message
233
232
  end
234
- assert_nothing_raised { ExceptionHandling.ensure_safe("mooo") { raise "Some BS" } }
233
+ assert_nothing_raised { ExceptionHandling.ensure_safe("mooo") { raise "Some Exception" } }
235
234
  assert log_info_messages.find { |message| message =~ /Unable to execute custom custom_data_hook callback/ }
236
- ExceptionHandling.custom_data_hook = nil
237
235
  end
238
236
  end
239
237
 
240
238
  context "Exception Handling" do
241
- setup do
242
- ActionMailer::Base.deliveries.clear
243
- ExceptionHandling.send(:clear_exception_summary)
244
- end
245
-
246
239
  context "default_metric_name" do
247
-
248
240
  context "when metric_name is present in exception_data" do
249
241
  should "include metric_name in resulting metric name" do
250
242
  exception = StandardError.new('this is an exception')
@@ -311,7 +303,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
311
303
  context "ExceptionHandling.ensure_safe" do
312
304
  should "log an exception with call stack if an exception is raised." do
313
305
  mock(ExceptionHandling.logger).fatal(/\(blah\):\n.*exception_handling_test\.rb/, anything)
314
- ExceptionHandling.ensure_safe { raise ArgumentError.new("blah") }
306
+ ExceptionHandling.ensure_safe { raise ArgumentError, "blah" }
315
307
  end
316
308
 
317
309
  should "log an exception with call stack if an ActionView template exception is raised." do
@@ -332,13 +324,13 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
332
324
 
333
325
  should "return nil if an exception is raised during an assignment" do
334
326
  mock(ExceptionHandling.logger).fatal(/\(blah\):\n.*exception_handling_test\.rb/, anything)
335
- b = ExceptionHandling.ensure_safe { raise ArgumentError.new("blah") }
327
+ b = ExceptionHandling.ensure_safe { raise ArgumentError, "blah" }
336
328
  assert_nil b
337
329
  end
338
330
 
339
331
  should "allow a message to be appended to the error when logged." do
340
332
  mock(ExceptionHandling.logger).fatal(/mooo \(blah\):\n.*exception_handling_test\.rb/, anything)
341
- b = ExceptionHandling.ensure_safe("mooo") { raise ArgumentError.new("blah") }
333
+ b = ExceptionHandling.ensure_safe("mooo") { raise ArgumentError, "blah" }
342
334
  assert_nil b
343
335
  end
344
336
 
@@ -347,7 +339,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
347
339
 
348
340
  mock(ExceptionHandling.logger).fatal(/mooo \(blah\):\n.*exception_handling_test\.rb/, anything)
349
341
 
350
- b = ExceptionHandling.ensure_safe("mooo") { raise StandardError.new("blah") }
342
+ b = ExceptionHandling.ensure_safe("mooo") { raise StandardError, "blah" }
351
343
  assert_nil b
352
344
  end
353
345
  end
@@ -355,7 +347,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
355
347
  context "ExceptionHandling.ensure_completely_safe" do
356
348
  should "log an exception if an exception is raised." do
357
349
  mock(ExceptionHandling.logger).fatal(/\(blah\):\n.*exception_handling_test\.rb/, anything)
358
- ExceptionHandling.ensure_completely_safe { raise ArgumentError.new("blah") }
350
+ ExceptionHandling.ensure_completely_safe { raise ArgumentError, "blah" }
359
351
  end
360
352
 
361
353
  should "should not log an exception if an exception is not raised." do
@@ -371,26 +363,26 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
371
363
 
372
364
  should "return nil if an exception is raised during an assignment" do
373
365
  mock(ExceptionHandling.logger).fatal(/\(blah\):\n.*exception_handling_test\.rb/, anything) { nil }
374
- b = ExceptionHandling.ensure_completely_safe { raise ArgumentError.new("blah") }
366
+ b = ExceptionHandling.ensure_completely_safe { raise ArgumentError, "blah" }
375
367
  assert_nil b
376
368
  end
377
369
 
378
370
  should "allow a message to be appended to the error when logged." do
379
371
  mock(ExceptionHandling.logger).fatal(/mooo \(blah\):\n.*exception_handling_test\.rb/, anything)
380
- b = ExceptionHandling.ensure_completely_safe("mooo") { raise ArgumentError.new("blah") }
372
+ b = ExceptionHandling.ensure_completely_safe("mooo") { raise ArgumentError, "blah" }
381
373
  assert_nil b
382
374
  end
383
375
 
384
376
  should "rescue any instance or child of Exception" do
385
377
  mock(ExceptionHandling.logger).fatal(/\(blah\):\n.*exception_handling_test\.rb/, anything)
386
- ExceptionHandling::ensure_completely_safe { raise Exception.new("blah") }
378
+ ExceptionHandling.ensure_completely_safe { raise Exception, "blah" }
387
379
  end
388
380
 
389
381
  should "not rescue the special exceptions that Ruby uses" do
390
382
  [SystemExit, SystemStackError, NoMemoryError, SecurityError].each do |exception|
391
383
  assert_raise exception do
392
384
  ExceptionHandling.ensure_completely_safe do
393
- raise exception.new
385
+ raise exception
394
386
  end
395
387
  end
396
388
  end
@@ -398,11 +390,17 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
398
390
  end
399
391
 
400
392
  context "ExceptionHandling.ensure_escalation" do
393
+ setup do
394
+ capture_notifications
395
+ ActionMailer::Base.deliveries.clear
396
+ end
397
+
401
398
  should "log the exception as usual and send the proper email" do
402
- assert_equal 0, ActionMailer::Base.deliveries.count
403
399
  mock(ExceptionHandling.logger).fatal(/\(blah\):\n.*exception_handling_test\.rb/, anything)
404
- ExceptionHandling.ensure_escalation( "Favorite Feature") { raise ArgumentError.new("blah") }
405
- assert_equal 2, ActionMailer::Base.deliveries.count
400
+ ExceptionHandling.ensure_escalation("Favorite Feature") { raise ArgumentError, "blah" }
401
+ assert_equal 1, ActionMailer::Base.deliveries.count
402
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect
403
+
406
404
  email = ActionMailer::Base.deliveries.last
407
405
  assert_equal "#{ExceptionHandling.email_environment} Escalation: Favorite Feature", email.subject
408
406
  assert_match 'ArgumentError: blah', email.body.to_s
@@ -410,23 +408,42 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
410
408
  end
411
409
 
412
410
  should "should not escalate if an exception is not raised." do
413
- assert_equal 0, ActionMailer::Base.deliveries.count
414
411
  dont_allow(ExceptionHandling.logger).fatal
415
412
  ExceptionHandling.ensure_escalation('Ignored') { ; }
416
413
  assert_equal 0, ActionMailer::Base.deliveries.count
417
414
  end
418
415
 
419
- should "log if the escalation email can not be sent" do
416
+ should "log if the escalation email cannot be sent" do
420
417
  any_instance_of(Mail::Message) do |message|
421
- mock(message).deliver
422
418
  mock(message).deliver { raise RuntimeError.new, "Delivery Error" }
423
419
  end
424
- mock(ExceptionHandling.logger) do |logger|
425
- logger.fatal(/first_test_exception/, anything)
426
- logger.fatal(/safe_email_deliver .*Delivery Error/, anything)
420
+ log_fatals = []
421
+ stub(ExceptionHandling.logger) do |logger|
422
+ logger.fatal.with_any_args { |*args| log_fatals << args }
427
423
  end
428
- ExceptionHandling.ensure_escalation("Not Used") { raise ArgumentError.new("first_test_exception") }
429
- assert_equal 0, ActionMailer::Base.deliveries.count
424
+
425
+ ExceptionHandling.ensure_escalation("ensure context") { raise ArgumentError, "first_test_exception" }
426
+
427
+ assert_match /ArgumentError.*first_test_exception/, log_fatals[0].first
428
+ assert_match /safe_email_deliver.*Delivery Error/, log_fatals[1].first
429
+
430
+ assert_equal 2, log_fatals.size, log_fatals.inspect
431
+
432
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect # still sent to honeybadger
433
+ end
434
+
435
+ should "allow the caller to specify custom recipients" do
436
+ custom_recipients = ['something@invoca.com']
437
+ mock(ExceptionHandling.logger).fatal(/\(blah\):\n.*exception_handling_test\.rb/, anything)
438
+ ExceptionHandling.ensure_escalation("Favorite Feature", custom_recipients) { raise ArgumentError, "blah" }
439
+ assert_equal 1, ActionMailer::Base.deliveries.count
440
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect
441
+
442
+ email = ActionMailer::Base.deliveries.last
443
+ assert_equal "#{ExceptionHandling.email_environment} Escalation: Favorite Feature", email.subject
444
+ assert_match 'ArgumentError: blah', email.body.to_s
445
+ assert_match ExceptionHandling.last_exception_timestamp.to_s, email.body.to_s
446
+ assert_equal custom_recipients, email.to
430
447
  end
431
448
  end
432
449
 
@@ -434,7 +451,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
434
451
  should "log the exception as usual and fire a sensu event" do
435
452
  mock(ExceptionHandling::Sensu).generate_event("Favorite Feature", "test context\nblah")
436
453
  mock(ExceptionHandling.logger).fatal(/\(blah\):\n.*exception_handling_test\.rb/, anything)
437
- ExceptionHandling.ensure_alert('Favorite Feature', 'test context') { raise ArgumentError.new("blah") }
454
+ ExceptionHandling.ensure_alert('Favorite Feature', 'test context') { raise ArgumentError, "blah" }
438
455
  end
439
456
 
440
457
  should "should not send sensu event if an exception is not raised." do
@@ -449,7 +466,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
449
466
  logger.fatal(/first_test_exception/, anything)
450
467
  logger.fatal(/Failed to send/, anything)
451
468
  end
452
- ExceptionHandling.ensure_alert("Not Used", 'test context') { raise ArgumentError.new("first_test_exception") }
469
+ ExceptionHandling.ensure_alert("Not Used", 'test context') { raise ArgumentError, "first_test_exception" }
453
470
  end
454
471
 
455
472
  should "log if the exception message is nil" do
@@ -465,141 +482,53 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
465
482
  recipients = ["prodsupport@example.com"]
466
483
 
467
484
  mock(ExceptionHandling).production_support_recipients { recipients }.times(2)
468
- mock(ExceptionHandling).escalate_custom(subject, exception, ExceptionHandling.last_exception_timestamp, recipients)
485
+ mock(ExceptionHandling).escalate(subject, exception, ExceptionHandling.last_exception_timestamp, recipients)
469
486
  ExceptionHandling.escalate_to_production_support(exception, subject)
470
487
  end
471
488
  end
472
489
 
473
490
  context "exception timestamp" do
474
491
  setup do
475
- Time.now_override = Time.parse( '1986-5-21 4:17 am UTC' )
492
+ Time.now_override = Time.parse('1986-5-21 4:17 am UTC')
476
493
  end
477
494
 
478
495
  should "include the timestamp when the exception is logged" do
479
- mock(ExceptionHandling.logger).fatal(/\(Error:517033020\) ArgumentError mooo \(blah\):\n.*exception_handling_test\.rb/, anything)
480
- b = ExceptionHandling.ensure_safe("mooo") { raise ArgumentError.new("blah") }
481
- assert_nil b
482
-
483
- assert_equal 517033020, ExceptionHandling.last_exception_timestamp
496
+ capture_notifications
484
497
 
485
- assert_emails 1
486
- assert_match(/517033020/, ActionMailer::Base.deliveries[-1].body.to_s)
487
- end
488
- end
489
-
490
- should "send just one copy of exceptions that don't repeat" do
491
- ExceptionHandling.log_error(exception_1)
492
- ExceptionHandling.log_error(exception_2)
493
- assert_emails 2
494
- assert_match(/Exception 1/, ActionMailer::Base.deliveries[-2].subject)
495
- assert_match(/Exception 2/, ActionMailer::Base.deliveries[-1].subject)
496
- end
498
+ mock(ExceptionHandling.logger).fatal(/\(Error:517033020\) ArgumentError context \(blah\):\n.*exception_handling_test\.rb/, anything)
499
+ b = ExceptionHandling.ensure_safe("context") { raise ArgumentError, "blah" }
500
+ assert_nil b
497
501
 
498
- should "not send emails if exception is a warning" do
499
- ExceptionHandling.log_error(ExceptionHandling::Warning.new("Don't send email"))
500
- assert_emails 0
501
- end
502
+ assert_equal 517_033_020, ExceptionHandling.last_exception_timestamp
502
503
 
503
- should "not send emails when log_warning is called" do
504
- ExceptionHandling.log_warning("Don't send email")
505
- assert_emails 0
506
- end
504
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect
507
505
 
508
- should "log the error if the exception message is nil" do
509
- ExceptionHandling.log_error(exception_with_nil_message)
510
- assert_emails(1)
511
- assert_match(/RuntimeError/, ActionMailer::Base.deliveries.last.subject)
512
- end
513
-
514
- should "log the error if the exception message is nil and the exception context is a hash" do
515
- ExceptionHandling.log_error(exception_with_nil_message, "SERVER_NAME" => "exceptional.com")
516
- assert_emails(1)
517
- assert_match(/RuntimeError/, ActionMailer::Base.deliveries.last.subject)
518
- end
519
-
520
- should "only send 5 of a repeated error, but call post hook for every exception" do
521
- @fail_count = 0
522
- ExceptionHandling.post_log_error_hook = method(:log_error_callback)
523
- assert_emails 5 do
524
- 10.times do
525
- ExceptionHandling.log_error(exception_1)
526
- end
506
+ assert_equal 517_033_020, sent_notifications.last.enhanced_data['timestamp']
527
507
  end
528
- assert_equal 10, @fail_count
529
508
  end
530
509
 
531
- should "only send 5 of a repeated error but don't send summary if 6th is different" do
532
- assert_emails 5 do
533
- 5.times do
534
- ExceptionHandling.log_error(exception_1)
535
- end
536
- end
537
- assert_emails 1 do
538
- ExceptionHandling.log_error(exception_2)
539
- end
540
- end
541
-
542
- should "send the summary when the error is encountered an hour after the first occurrence" do
543
- assert_emails 5 do # 5 exceptions, 4 summarized
544
- 9.times do |t|
545
- ExceptionHandling.log_error(exception_1)
546
- end
547
- end
548
- Time.now_override = 2.hours.from_now
549
- assert_emails 1 do # 1 summary (4 + 1 = 5) after 2 hours
550
- ExceptionHandling.log_error(exception_1)
551
- end
552
- assert_match(/\[5 SUMMARIZED\]/, ActionMailer::Base.deliveries.last.subject)
553
- assert_match(/This exception occurred 5 times since/, ActionMailer::Base.deliveries.last.body.to_s)
554
-
555
- assert_emails 0 do # still summarizing...
556
- 7.times do
557
- ExceptionHandling.log_error(exception_1)
558
- end
559
- end
510
+ should "log the error if the exception message is nil" do
511
+ capture_notifications
560
512
 
561
- Time.now_override = 3.hours.from_now
513
+ ExceptionHandling.log_error(exception_with_nil_message)
562
514
 
563
- assert_emails 1 + 2 do # 1 summary and 2 new
564
- 2.times do
565
- ExceptionHandling.log_error(exception_2)
566
- end
567
- end
568
- assert_match(/\[7 SUMMARIZED\]/, ActionMailer::Base.deliveries[-3].subject)
569
- assert_match(/This exception occurred 7 times since/, ActionMailer::Base.deliveries[-3].body.to_s)
515
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect
516
+ assert_equal 'RuntimeError: ', sent_notifications.last.enhanced_data['error_string']
570
517
  end
571
518
 
572
- should "send the summary if a summary is available, but not sent when another exception comes up" do
573
- assert_emails 5 do # 5 to start summarizing
574
- 6.times do
575
- ExceptionHandling.log_error(exception_1)
576
- end
577
- end
578
-
579
- assert_emails 1 + 1 do # 1 summary of previous, 1 from new exception
580
- ExceptionHandling.log_error(exception_2)
581
- end
582
-
583
- assert_match(/\[1 SUMMARIZED\]/, ActionMailer::Base.deliveries[-2].subject)
584
- assert_match(/This exception occurred 1 times since/, ActionMailer::Base.deliveries[-2].body.to_s)
519
+ should "log the error if the exception message is nil and the exception context is a hash" do
520
+ capture_notifications
585
521
 
586
- assert_emails 5 do # 5 to start summarizing
587
- 10.times do
588
- ExceptionHandling.log_error(exception_1)
589
- end
590
- end
522
+ ExceptionHandling.log_error(exception_with_nil_message, "SERVER_NAME" => "exceptional.com")
591
523
 
592
- assert_emails 0 do # still summarizing
593
- 11.times do
594
- ExceptionHandling.log_error(exception_1)
595
- end
596
- end
524
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect
525
+ assert_equal 'RuntimeError: ', sent_notifications.last.enhanced_data['error_string']
597
526
  end
598
527
 
599
528
  context "Honeybadger integration" do
600
529
  context "with Honeybadger not defined" do
601
530
  setup do
602
- stub(ExceptionHandling).honeybadger? { false }
531
+ stub(ExceptionHandling).honeybadger_defined? { false }
603
532
  end
604
533
 
605
534
  should "not invoke send_exception_to_honeybadger when log_error is executed" do
@@ -649,16 +578,17 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
649
578
  should "send error details and relevant context data to Honeybadger" do
650
579
  Time.now_override = Time.now
651
580
  env = { server: "fe98" }
652
- parameters = { advertiser_id: 435 }
581
+ parameters = { advertiser_id: 435, controller: "some_controller" }
653
582
  session = { username: "jsmith" }
654
583
  request_uri = "host/path"
655
584
  controller = create_dummy_controller(env, parameters, session, request_uri)
656
585
  stub(ExceptionHandling).server_name { "invoca_fe98" }
657
586
 
658
- exception = StandardError.new("Some BS")
587
+ exception = StandardError.new("Some Exception")
659
588
  exception.set_backtrace([
660
- "test/unit/exception_handling_test.rb:847:in `exception_1'",
661
- "test/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"])
589
+ "test/unit/exception_handling_test.rb:847:in `exception_1'",
590
+ "test/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"
591
+ ])
662
592
  exception_context = { "SERVER_NAME" => "exceptional.com" }
663
593
 
664
594
  honeybadger_data = nil
@@ -673,8 +603,9 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
673
603
  end
674
604
 
675
605
  expected_data = {
676
- error_class: :"Test BS",
677
- error_message: "Some BS",
606
+ error_class: :"Test Exception",
607
+ error_message: "Some Exception",
608
+ controller: "some_controller",
678
609
  exception: exception,
679
610
  context: {
680
611
  timestamp: Time.now.to_i,
@@ -685,25 +616,33 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
685
616
  notes: "this is used by a test",
686
617
  user_details: { "username" => "jsmith" },
687
618
  request: {
688
- "params" => { "advertiser_id" => 435 },
619
+ "params" => { "advertiser_id" => 435, "controller" => "some_controller" },
689
620
  "rails_root" => "Rails.root not defined. Is this a test environment?",
690
- "url" => "host/path" },
621
+ "url" => "host/path"
622
+ },
691
623
  session: {
692
624
  "key" => nil,
693
- "data" => { "username" => "jsmith" } },
625
+ "data" => { "username" => "jsmith" }
626
+ },
694
627
  environment: {
695
- "SERVER_NAME" => "exceptional.com" },
628
+ "SERVER_NAME" => "exceptional.com"
629
+ },
696
630
  backtrace: [
697
631
  "test/unit/exception_handling_test.rb:847:in `exception_1'",
698
- "test/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"],
632
+ "test/unit/exception_handling_test.rb:455:in `block (4 levels) in <class:ExceptionHandlingTest>'"
633
+ ],
699
634
  event_response: "Event successfully received"
700
635
  }
701
636
  }
702
637
  assert_equal_with_diff expected_data, honeybadger_data
703
638
  end
704
639
 
705
- should "not send notification to honeybadger when exception description has the flag turned off and call log error callback with logged_to_honeybadger set to nil" do
706
- begin
640
+ context "with post_log_error_hook set" do
641
+ teardown do
642
+ ExceptionHandling.post_log_error_hook = nil
643
+ end
644
+
645
+ should "not send notification to honeybadger when exception description has the flag turned off and call log error callback with logged_to_honeybadger set to nil" do
707
646
  @fail_count = 0
708
647
  @honeybadger_status = nil
709
648
  ExceptionHandling.post_log_error_hook = method(:log_error_callback_config)
@@ -716,55 +655,37 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
716
655
  stub(File).mtime { incrementing_mtime }
717
656
  mock(YAML).load_file.with_any_args { ActiveSupport::HashWithIndifferentAccess.new(filter_list) }.at_least(1)
718
657
 
719
- exception = StandardError.new("suppress Honeybadger notification")
720
- mock.proxy(ExceptionHandling).send_exception_to_honeybadger.with_any_args.once
658
+ mock.proxy(ExceptionHandling).send_exception_to_honeybadger_unless_filtered.with_any_args.once
721
659
  dont_allow(Honeybadger).notify
722
- ExceptionHandling.log_error(exception)
660
+ ExceptionHandling.log_error(StandardError.new("suppress Honeybadger notification"))
723
661
  assert_equal :skipped, @honeybadger_status
724
- ensure
725
- ExceptionHandling.post_log_error_hook = nil
726
662
  end
727
- end
728
663
 
729
- should "call log error callback with logged_to_honeybadger set to false if an error occurs while attempting to notify honeybadger" do
730
- begin
664
+ should "call log error callback with logged_to_honeybadger set to false if an error occurs while attempting to notify honeybadger" do
731
665
  @fail_count = 0
732
666
  @honeybadger_status = nil
733
667
  ExceptionHandling.post_log_error_hook = method(:log_error_callback_config)
734
- stub($stderr).puts
735
668
  mock(Honeybadger).notify.with_any_args { raise "Honeybadger Notification Failure" }
736
669
  ExceptionHandling.log_error(exception_1)
737
670
  assert_equal :failure, @honeybadger_status
738
- ensure
739
- ExceptionHandling.post_log_error_hook = nil
740
671
  end
741
- end
742
672
 
743
- should "call log error callback with logged_to_honeybadger set to false on unsuccessful honeybadger notification" do
744
- begin
673
+ should "call log error callback with logged_to_honeybadger set to false on unsuccessful honeybadger notification" do
745
674
  @fail_count = 0
746
675
  @honeybadger_status = nil
747
676
  ExceptionHandling.post_log_error_hook = method(:log_error_callback_config)
748
- stub($stderr).puts
749
677
  mock(Honeybadger).notify.with_any_args { false }
750
678
  ExceptionHandling.log_error(exception_1)
751
679
  assert_equal :failure, @honeybadger_status
752
- ensure
753
- ExceptionHandling.post_log_error_hook = nil
754
680
  end
755
- end
756
681
 
757
- should "call log error callback with logged_to_honeybadger set to true on successful honeybadger notification" do
758
- begin
682
+ should "call log error callback with logged_to_honeybadger set to true on successful honeybadger notification" do
759
683
  @fail_count = 0
760
684
  @honeybadger_status = nil
761
685
  ExceptionHandling.post_log_error_hook = method(:log_error_callback_config)
762
- stub($stderr).puts
763
686
  mock(Honeybadger).notify.with_any_args { '06220c5a-b471-41e5-baeb-de247da45a56' }
764
687
  ExceptionHandling.log_error(exception_1)
765
688
  assert_equal :success, @honeybadger_status
766
- ensure
767
- ExceptionHandling.post_log_error_hook = nil
768
689
  end
769
690
  end
770
691
  end
@@ -777,20 +698,27 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
777
698
  end
778
699
 
779
700
  should "allow sections to have data with just a to_s method" do
780
- ExceptionHandling.log_error("This is my RingSwitch example. Log, don't email!") do |data|
781
- data.merge!(:event_response => EventResponse.new)
701
+ capture_notifications
702
+
703
+ ExceptionHandling.log_error("This is my RingSwitch example.") do |data|
704
+ data.merge!(event_response: EventResponse.new)
782
705
  end
783
- assert_emails 1
784
- assert_match(/message from to_s!/, ActionMailer::Base.deliveries.last.body.to_s)
706
+
707
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect
708
+ assert_match(/message from to_s!/, sent_notifications.last.enhanced_data['event_response'].to_s)
785
709
  end
786
710
  end
787
711
 
712
+ should "return the error ID (timestamp)" do
713
+ result = ExceptionHandling.log_error(RuntimeError.new("A runtime error"), "Runtime message")
714
+ assert_equal ExceptionHandling.last_exception_timestamp, result
715
+ end
716
+
788
717
  should "rescue exceptions that happen in log_error" do
789
- stub(ExceptionHandling).make_exception { raise ArgumentError.new("Bad argument") }
718
+ stub(ExceptionHandling).make_exception { raise ArgumentError, "Bad argument" }
790
719
  mock(ExceptionHandling).write_exception_to_log(satisfy { |ex| ex.to_s['Bad argument'] },
791
720
  satisfy { |context| context['ExceptionHandlingError: log_error rescued exception while logging Runtime message'] },
792
721
  anything)
793
- stub($stderr).puts
794
722
  ExceptionHandling.log_error(RuntimeError.new("A runtime error"), "Runtime message")
795
723
  end
796
724
 
@@ -799,13 +727,13 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
799
727
  satisfy { |context| context['Context message'] },
800
728
  anything,
801
729
  anything)
802
- ExceptionHandling.log_error(ArgumentError.new("Bad argument"), "Context message") { |data| raise 'Error!!!' }
730
+ ExceptionHandling.log_error(ArgumentError.new("Bad argument"), "Context message") { |_data| raise 'Error!!!' }
803
731
  end
804
732
 
805
733
  context "Exception Filtering" do
806
734
  setup do
807
- filter_list = { :exception1 => { 'error' => "my error message" },
808
- :exception2 => { 'error' => "some other message", :session => "misc data" } }
735
+ filter_list = { exception1: { 'error' => "my error message" },
736
+ exception2: { 'error' => "some other message", :session => "misc data" } }
809
737
  stub(YAML).load_file { ActiveSupport::HashWithIndifferentAccess.new(filter_list) }
810
738
 
811
739
  # bump modified time up to get the above filter loaded
@@ -813,105 +741,119 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
813
741
  end
814
742
 
815
743
  should "handle case where filter list is not found" do
816
- stub(YAML).load_file { raise Errno::ENOENT.new("File not found") }
744
+ stub(YAML).load_file { raise Errno::ENOENT, "File not found" }
745
+
746
+ capture_notifications
817
747
 
818
- ActionMailer::Base.deliveries.clear
819
- ExceptionHandling.log_error( "My error message is in list" )
820
- assert_emails 1
748
+ ExceptionHandling.log_error("My error message is in list")
749
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect
821
750
  end
822
751
 
823
752
  should "log exception and suppress email when exception is on filter list" do
824
- ActionMailer::Base.deliveries.clear
825
- ExceptionHandling.log_error( "Error message is not in list" )
826
- assert_emails 1
753
+ capture_notifications
827
754
 
828
- ActionMailer::Base.deliveries.clear
829
- ExceptionHandling.log_error( "My error message is in list" )
830
- assert_emails 0
755
+ ExceptionHandling.log_error("Error message is not in list")
756
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect
757
+
758
+ sent_notifications.clear
759
+ ExceptionHandling.log_error("My error message is in list")
760
+ assert_equal 0, sent_notifications.size, sent_notifications.inspect
831
761
  end
832
762
 
833
763
  should "allow filtering exception on any text in exception data" do
834
- filters = { :exception1 => { :session => "data: my extra session data" } }
764
+ filters = { exception1: { session: "data: my extra session data" } }
835
765
  stub(YAML).load_file { ActiveSupport::HashWithIndifferentAccess.new(filters) }
836
766
 
837
- ActionMailer::Base.deliveries.clear
838
- ExceptionHandling.log_error( "No match here" ) do |data|
767
+ capture_notifications
768
+
769
+ ExceptionHandling.log_error("No match here") do |data|
839
770
  data[:session] = {
840
- :key => "@session_id",
841
- :data => "my extra session data"
842
- }
771
+ key: "@session_id",
772
+ data: "my extra session data"
773
+ }
843
774
  end
844
- assert_emails 0
775
+ assert_equal 0, sent_notifications.size, sent_notifications.inspect
845
776
 
846
- ActionMailer::Base.deliveries.clear
847
- ExceptionHandling.log_error( "No match here" ) do |data|
777
+ ExceptionHandling.log_error("No match here") do |data|
848
778
  data[:session] = {
849
- :key => "@session_id",
850
- :data => "my extra session <no match!> data"
851
- }
779
+ key: "@session_id",
780
+ data: "my extra session <no match!> data"
781
+ }
852
782
  end
853
- assert_emails 1, ActionMailer::Base.deliveries.*.body.*.inspect
783
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect
854
784
  end
855
785
 
856
786
  should "reload filter list on the next exception if file was modified" do
857
- ActionMailer::Base.deliveries.clear
858
- ExceptionHandling.log_error( "Error message is not in list" )
859
- assert_emails 1
787
+ capture_notifications
788
+
789
+ ExceptionHandling.log_error("Error message is not in list")
790
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect
860
791
 
861
- filter_list = { :exception1 => { 'error' => "Error message is not in list" } }
792
+ filter_list = { exception1: { 'error' => "Error message is not in list" } }
862
793
  stub(YAML).load_file { ActiveSupport::HashWithIndifferentAccess.new(filter_list) }
863
794
  stub(File).mtime { incrementing_mtime }
864
795
 
865
- ActionMailer::Base.deliveries.clear
866
- ExceptionHandling.log_error( "Error message is not in list" )
867
- assert_emails 0, ActionMailer::Base.deliveries.*.body.*.inspect
796
+ sent_notifications.clear
797
+ ExceptionHandling.log_error("Error message is not in list")
798
+ assert_equal 0, sent_notifications.size, sent_notifications.inspect
868
799
  end
869
800
 
870
801
  should "not consider filter if both error message and body do not match" do
802
+ capture_notifications
803
+
871
804
  # error message matches, but not full text
872
- ActionMailer::Base.deliveries.clear
873
- ExceptionHandling.log_error( "some other message" )
874
- assert_emails 1, ActionMailer::Base.deliveries.*.body.*.inspect
805
+ ExceptionHandling.log_error("some other message")
806
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect
875
807
 
876
808
  # now both match
877
- ActionMailer::Base.deliveries.clear
878
- ExceptionHandling.log_error( "some other message" ) do |data|
879
- data[:session] = {:some_random_key => "misc data"}
809
+ sent_notifications.clear
810
+ ExceptionHandling.log_error("some other message") do |data|
811
+ data[:session] = { some_random_key: "misc data" }
880
812
  end
881
- assert_emails 0, ActionMailer::Base.deliveries.*.body.*.inspect
813
+ assert_equal 0, sent_notifications.size, sent_notifications.inspect
882
814
  end
883
815
 
884
816
  should "skip environment keys not on whitelist" do
885
- ActionMailer::Base.deliveries.clear
886
- ExceptionHandling.log_error( "some message" ) do |data|
887
- data[:environment] = { :SERVER_PROTOCOL => "HTTP/1.0", :RAILS_SECRETS_YML_CONTENTS => 'password: VERY_SECRET_PASSWORD' }
817
+ capture_notifications
818
+
819
+ ExceptionHandling.log_error("some message") do |data|
820
+ data[:environment] = { SERVER_PROTOCOL: "HTTP/1.0", RAILS_SECRETS_YML_CONTENTS: 'password: VERY_SECRET_PASSWORD' }
888
821
  end
889
- assert_emails 1, ActionMailer::Base.deliveries.*.body.*.inspect
890
- mail = ActionMailer::Base.deliveries.last
891
- assert_nil mail.body.to_s["RAILS_SECRETS_YML_CONTENTS"], mail.body.to_s # this is not on whitelist
892
- assert mail.body.to_s["SERVER_PROTOCOL: HTTP/1.0" ], mail.body.to_s # this is
822
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect
823
+
824
+ mail = sent_notifications.last
825
+ environment = mail.enhanced_data['environment']
826
+
827
+ assert_nil environment["RAILS_SECRETS_YML_CONTENTS"], environment.inspect # this is not on whitelist
828
+ assert environment["SERVER_PROTOCOL"], environment.inspect # this is
893
829
  end
894
830
 
895
831
  should "omit environment defaults" do
896
- ActionMailer::Base.deliveries.clear
897
- ExceptionHandling.log_error( "some message" ) do |data|
898
- data[:environment] = {:SERVER_PORT => '80', :SERVER_PROTOCOL => "HTTP/1.0"}
832
+ capture_notifications
833
+
834
+ stub(ExceptionHandling).send_exception_to_honeybadger(anything) { |exception_info| sent_notifications << exception_info }
835
+
836
+ ExceptionHandling.log_error("some message") do |data|
837
+ data[:environment] = { SERVER_PORT: '80', SERVER_PROTOCOL: "HTTP/1.0" }
899
838
  end
900
- assert_emails 1, ActionMailer::Base.deliveries.*.body.*.inspect
901
- mail = ActionMailer::Base.deliveries.last
902
- assert_nil mail.body.to_s["SERVER_PORT" ], mail.body.to_s # this was default
903
- assert mail.body.to_s["SERVER_PROTOCOL: HTTP/1.0"], mail.body.to_s # this was not
839
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect
840
+ mail = sent_notifications.last
841
+ environment = mail.enhanced_data['environment']
842
+
843
+ assert_nil environment["SERVER_PORT"], environment.inspect # this was default
844
+ assert environment["SERVER_PROTOCOL"], environment # this was not
904
845
  end
905
846
 
906
847
  should "reject the filter file if any contain all empty regexes" do
907
- filter_list = { :exception1 => { 'error' => "", :session => "" },
908
- :exception2 => { 'error' => "is not in list", :session => "" } }
848
+ filter_list = { exception1: { 'error' => "", :session => "" },
849
+ exception2: { 'error' => "is not in list", :session => "" } }
909
850
  stub(YAML).load_file { ActiveSupport::HashWithIndifferentAccess.new(filter_list) }
910
851
  stub(File).mtime { incrementing_mtime }
911
852
 
912
- ActionMailer::Base.deliveries.clear
913
- ExceptionHandling.log_error( "Error message is not in list" )
914
- assert_emails 1, ActionMailer::Base.deliveries.*.inspect
853
+ capture_notifications
854
+
855
+ ExceptionHandling.log_error("Error message is not in list")
856
+ assert_equal 1, sent_notifications.size, sent_notifications.inspect
915
857
  end
916
858
 
917
859
  should "reload filter file if filename changes" do
@@ -921,27 +863,13 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
921
863
  end
922
864
 
923
865
  context "Exception Handling Mailer" do
924
- should "create email" do
925
- ExceptionHandling.log_error(exception_1) do |data|
926
- data[:request] = { :params => {:id => 10993}, :url => "www.ringrevenue.com" }
927
- data[:session] = { :key => "DECAFE" }
928
- end
929
- assert_emails 1, ActionMailer::Base.deliveries.*.inspect
930
- assert mail = ActionMailer::Base.deliveries.last
931
- assert_equal ['exceptions@example.com'], mail.to
932
- assert_equal ['server@example.com'].to_s, mail.from.to_s
933
- assert_match(/Exception 1/, mail.to_s)
934
- assert_match(/key: DECAFE/, mail.to_s)
935
- assert_match(/id: 10993/, mail.to_s)
936
- end
937
-
938
866
  EXPECTED_SMTP_HASH =
939
- {
940
- :host => '127.0.0.1',
941
- :domain => 'localhost.localdomain',
942
- :from => 'server@example.com',
943
- :to => 'exceptions@example.com'
944
- }
867
+ {
868
+ host: '127.0.0.1',
869
+ domain: 'localhost.localdomain',
870
+ from: 'server@example.com',
871
+ to: 'escalation@example.com'
872
+ }.freeze
945
873
 
946
874
  [[true, false], [true, true]].each do |em_flag, synchrony_flag|
947
875
  context "eventmachine_safe = #{em_flag} && eventmachine_synchrony = #{synchrony_flag}" do
@@ -961,22 +889,24 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
961
889
  end
962
890
 
963
891
  should "schedule EventMachine STMP when EventMachine defined" do
892
+ ActionMailer::Base.deliveries.clear
893
+
964
894
  set_test_const('EventMachine::Protocols::SmtpClient', SmtpClientStub)
965
895
 
966
- ExceptionHandling.log_error(exception_1)
896
+ ExceptionHandling.ensure_escalation("ensure message") { raise 'Exception to escalate!' }
967
897
  assert EventMachineStub.block
968
898
  EventMachineStub.block.call
969
899
  assert DNSResolvStub.callback_block
970
900
  DNSResolvStub.callback_block.call ['127.0.0.1']
971
- assert_equal_with_diff EXPECTED_SMTP_HASH, (SmtpClientStub.send_hash & EXPECTED_SMTP_HASH.keys).map_hash { |k,v| v.to_s }, SmtpClientStub.send_hash.inspect
901
+ assert_equal_with_diff EXPECTED_SMTP_HASH, (SmtpClientStub.send_hash & EXPECTED_SMTP_HASH.keys).map_hash { |_k, v| v.to_s }, SmtpClientStub.send_hash.inspect
972
902
  assert_equal((synchrony_flag ? :asend : :send), SmtpClientStub.last_method)
973
- assert_match(/Exception 1/, SmtpClientStub.send_hash[:content])
903
+ assert_match(/Exception to escalate/, SmtpClientStub.send_hash[:content])
974
904
  assert_emails 0, ActionMailer::Base.deliveries.*.to_s
975
905
  end
976
906
 
977
907
  should "pass the content as a proper rfc 2822 message" do
978
908
  set_test_const('EventMachine::Protocols::SmtpClient', SmtpClientStub)
979
- ExceptionHandling.log_error(exception_1)
909
+ ExceptionHandling.ensure_escalation("ensure message") { raise 'Exception to escalate!' }
980
910
  assert EventMachineStub.block
981
911
  EventMachineStub.block.call
982
912
  assert DNSResolvStub.callback_block
@@ -987,27 +917,26 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
987
917
  end
988
918
 
989
919
  should "log fatal on EventMachine STMP errback" do
990
- assert_emails 0, ActionMailer::Base.deliveries.*.to_s
920
+ ActionMailer::Base.deliveries.clear
921
+
991
922
  set_test_const('EventMachine::Protocols::SmtpClient', SmtpClientErrbackStub)
992
- mock(ExceptionHandling.logger).fatal(/Exception 1/, anything)
923
+ mock(ExceptionHandling.logger).fatal(/Exception to escalate/, anything)
993
924
  mock(ExceptionHandling.logger).fatal(/Failed to email by SMTP: "credential mismatch"/)
994
925
 
995
- ExceptionHandling.log_error(exception_1)
926
+ ExceptionHandling.ensure_escalation("ensure message") { raise 'Exception to escalate!' }
996
927
  assert EventMachineStub.block
997
928
  EventMachineStub.block.call
998
929
  assert DNSResolvStub.callback_block
999
930
  DNSResolvStub.callback_block.call(['127.0.0.1'])
1000
931
  SmtpClientErrbackStub.block.call("credential mismatch")
1001
- assert_equal_with_diff EXPECTED_SMTP_HASH, (SmtpClientErrbackStub.send_hash & EXPECTED_SMTP_HASH.keys).map_hash { |k,v| v.to_s }, SmtpClientErrbackStub.send_hash.inspect
1002
- #assert_emails 0, ActionMailer::Base.deliveries.*.to_s
932
+ assert_equal_with_diff EXPECTED_SMTP_HASH, (SmtpClientErrbackStub.send_hash & EXPECTED_SMTP_HASH.keys).map_hash { |_k, v| v.to_s }, SmtpClientErrbackStub.send_hash.inspect
1003
933
  end
1004
934
 
1005
935
  should "log fatal on EventMachine dns resolver errback" do
1006
- assert_emails 0, ActionMailer::Base.deliveries.*.to_s
1007
- mock(ExceptionHandling.logger).fatal(/Exception 1/, anything)
936
+ mock(ExceptionHandling.logger).fatal(/Exception to escalate/, anything)
1008
937
  mock(ExceptionHandling.logger).fatal(/Failed to resolv DNS for localhost: "softlayer sucks"/)
1009
938
 
1010
- ExceptionHandling.log_error(exception_1)
939
+ ExceptionHandling.ensure_escalation("ensure message") { raise 'Exception to escalate!' }
1011
940
  assert EventMachineStub.block
1012
941
  EventMachineStub.block.call
1013
942
  DNSResolvStub.errback_block.call("softlayer sucks")
@@ -1015,45 +944,31 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
1015
944
  end
1016
945
  end
1017
946
  end
1018
-
1019
- should "truncate email subject" do
1020
- ActionMailer::Base.deliveries.clear
1021
- text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLM".split('').join("123456789")
1022
- begin
1023
- raise text
1024
- rescue => ex
1025
- ExceptionHandling.log_error( ex )
1026
- end
1027
- assert_emails 1, ActionMailer::Base.deliveries.*.inspect
1028
- mail = ActionMailer::Base.deliveries.last
1029
- subject = "#{ExceptionHandling.email_environment} exception: RuntimeError: " + text
1030
- assert_equal subject[0,300], mail.subject
1031
- end
1032
947
  end
1033
948
 
1034
949
  context "Exception mapping" do
1035
950
  setup do
1036
951
  @data = {
1037
- :environment=>{
952
+ environment: {
1038
953
  'HTTP_HOST' => "localhost",
1039
954
  'HTTP_REFERER' => "http://localhost/action/controller/instance",
1040
955
  },
1041
- :session=>{
1042
- :data=>{
1043
- :affiliate_id=> defined?(Affiliate) ? Affiliate.first.id : '1',
1044
- :edit_mode=> true,
1045
- :advertiser_id=> defined?(Advertiser) ? Advertiser.first.id : '1',
1046
- :username_id=> defined?(Username) ? Username.first.id : '1',
1047
- :user_id=> defined?(User) ? User.first.id : '1',
1048
- :flash=>{},
1049
- :impersonated_organization_pk=> 'Advertiser_1'
956
+ session: {
957
+ data: {
958
+ affiliate_id: defined?(Affiliate) ? Affiliate.first.id : '1',
959
+ edit_mode: true,
960
+ advertiser_id: defined?(Advertiser) ? Advertiser.first.id : '1',
961
+ username_id: defined?(Username) ? Username.first.id : '1',
962
+ user_id: defined?(User) ? User.first.id : '1',
963
+ flash: {},
964
+ impersonated_organization_pk: 'Advertiser_1'
1050
965
  }
1051
966
  },
1052
- :request=>{},
1053
- :backtrace=>["[GEM_ROOT]/gems/actionpack-2.1.0/lib/action_controller/filters.rb:580:in `call_filters'", "[GEM_ROOT]/gems/actionpack-2.1.0/lib/action_controller/filters.rb:601:in `run_before_filters'"],
1054
- :api_key=>"none",
1055
- :error_class=>"StandardError",
1056
- :error=>'Some error message'
967
+ request: {},
968
+ backtrace: ["[GEM_ROOT]/gems/actionpack-2.1.0/lib/action_controller/filters.rb:580:in `call_filters'", "[GEM_ROOT]/gems/actionpack-2.1.0/lib/action_controller/filters.rb:601:in `run_before_filters'"],
969
+ api_key: "none",
970
+ error_class: "StandardError",
971
+ error: 'Some error message'
1057
972
  }
1058
973
  end
1059
974
 
@@ -1130,7 +1045,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
1130
1045
  should "take in additional key word args as logging context and pass them to the logger" do
1131
1046
  ExceptionHandling.log_periodically(:test_context_with_periodic, 30.minutes, "this will be written", service_name: 'exception_handling')
1132
1047
  assert_not_empty logged_excluding_reload_filter.last[:context]
1133
- assert_equal logged_excluding_reload_filter.last[:context], { service_name: 'exception_handling' }
1048
+ assert_equal logged_excluding_reload_filter.last[:context], service_name: 'exception_handling'
1134
1049
  end
1135
1050
 
1136
1051
  should "log immediately when we are expected to log" do
@@ -1164,7 +1079,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
1164
1079
  end
1165
1080
 
1166
1081
  def exception_1
1167
- @ex1 ||=
1082
+ @exception_1 ||=
1168
1083
  begin
1169
1084
  raise StandardError, "Exception 1"
1170
1085
  rescue => ex
@@ -1173,7 +1088,7 @@ class ExceptionHandlingTest < ActiveSupport::TestCase
1173
1088
  end
1174
1089
 
1175
1090
  def exception_2
1176
- @ex2 ||=
1091
+ @exception_2 ||=
1177
1092
  begin
1178
1093
  raise StandardError, "Exception 2"
1179
1094
  rescue => ex