exception_handling 2.11.3 → 3.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +0 -3
  3. data/.ruby-version +1 -1
  4. data/Gemfile +16 -16
  5. data/Gemfile.lock +114 -110
  6. data/README.md +3 -7
  7. data/Rakefile +11 -8
  8. data/exception_handling.gemspec +10 -12
  9. data/lib/exception_handling/exception_info.rb +10 -13
  10. data/lib/exception_handling/honeybadger_callbacks.rb +59 -0
  11. data/lib/exception_handling/log_stub_error.rb +1 -2
  12. data/lib/exception_handling/methods.rb +53 -6
  13. data/lib/exception_handling/testing.rb +10 -20
  14. data/lib/exception_handling/version.rb +1 -1
  15. data/lib/exception_handling.rb +30 -58
  16. data/semaphore_ci/setup.sh +3 -0
  17. data/{spec → test}/helpers/controller_helpers.rb +0 -0
  18. data/{spec → test}/helpers/exception_helpers.rb +2 -2
  19. data/{spec/spec_helper.rb → test/test_helper.rb} +42 -63
  20. data/test/unit/exception_handling/exception_catalog_test.rb +85 -0
  21. data/test/unit/exception_handling/exception_description_test.rb +82 -0
  22. data/{spec/unit/exception_handling/exception_info_spec.rb → test/unit/exception_handling/exception_info_test.rb} +114 -153
  23. data/test/unit/exception_handling/honeybadger_callbacks_test.rb +122 -0
  24. data/{spec/unit/exception_handling/log_error_stub_spec.rb → test/unit/exception_handling/log_error_stub_test.rb} +22 -38
  25. data/{spec/unit/exception_handling/mailer_spec.rb → test/unit/exception_handling/mailer_test.rb} +18 -17
  26. data/test/unit/exception_handling/methods_test.rb +84 -0
  27. data/test/unit/exception_handling/sensu_test.rb +52 -0
  28. data/test/unit/exception_handling_test.rb +1109 -0
  29. metadata +60 -115
  30. data/.github/workflows/pipeline.yml +0 -33
  31. data/.rspec +0 -3
  32. data/Appraisals +0 -13
  33. data/CHANGELOG.md +0 -109
  34. data/gemfiles/rails_5.gemfile +0 -18
  35. data/gemfiles/rails_6.gemfile +0 -18
  36. data/lib/exception_handling/escalate_callback.rb +0 -19
  37. data/lib/exception_handling/logging_methods.rb +0 -27
  38. data/spec/rake_test_warning_false.rb +0 -20
  39. data/spec/unit/exception_handling/escalate_callback_spec.rb +0 -81
  40. data/spec/unit/exception_handling/exception_catalog_spec.rb +0 -85
  41. data/spec/unit/exception_handling/exception_description_spec.rb +0 -82
  42. data/spec/unit/exception_handling/logging_methods_spec.rb +0 -38
  43. data/spec/unit/exception_handling/methods_spec.rb +0 -105
  44. data/spec/unit/exception_handling/sensu_spec.rb +0 -51
  45. data/spec/unit/exception_handling_spec.rb +0 -1254
@@ -4,7 +4,7 @@
4
4
 
5
5
  module ExceptionHandling
6
6
  module Testing
7
- class ControllerStubBase
7
+ class ControllerStub
8
8
 
9
9
  class Request
10
10
  attr_accessor :parameters, :protocol, :host, :request_uri, :env, :session_options
@@ -25,7 +25,7 @@ module ExceptionHandling
25
25
  attr_accessor :around_filter_method
26
26
 
27
27
  def around_filter(method)
28
- self.around_filter_method = method
28
+ ControllerStub.around_filter_method = method
29
29
  end
30
30
  end
31
31
 
@@ -44,6 +44,14 @@ module ExceptionHandling
44
44
  end
45
45
  end
46
46
 
47
+ def simulate_around_filter(&block)
48
+ set_current_controller(&block)
49
+ end
50
+
51
+ def controller_name
52
+ "ControllerStub"
53
+ end
54
+
47
55
  def action_name
48
56
  "test_action"
49
57
  end
@@ -51,27 +59,9 @@ module ExceptionHandling
51
59
  def complete_request_uri
52
60
  "#{@request.protocol}#{@request.host}#{@request.request_uri}"
53
61
  end
54
- end
55
-
56
- class LoggingMethodsControllerStub < ControllerStubBase
57
- include ExceptionHandling::LoggingMethods
58
-
59
- def controller_name
60
- "LoggingMethodsControllerStub"
61
- end
62
- end
63
62
 
64
- class MethodsControllerStub < ControllerStubBase
65
63
  include ExceptionHandling::Methods
66
64
  set_long_controller_action_timeout 2
67
-
68
- def simulate_around_filter(&block)
69
- set_current_controller(&block)
70
- end
71
-
72
- def controller_name
73
- "MethodsControllerStub"
74
- end
75
65
  end
76
66
  end
77
67
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ExceptionHandling
4
- VERSION = '2.11.3'
4
+ VERSION = '3.0.pre.1'
5
5
  end
@@ -1,21 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'digest'
4
3
  require 'timeout'
5
4
  require 'active_support'
6
- require 'active_support/core_ext'
5
+ require 'active_support/core_ext/hash'
7
6
  require 'contextual_logger'
8
7
 
9
8
  require 'invoca/utils'
10
9
 
11
- require 'exception_handling/mailer'
12
- require 'exception_handling/sensu'
13
- require 'exception_handling/methods'
14
- require 'exception_handling/log_stub_error'
15
- require 'exception_handling/exception_description'
16
- require 'exception_handling/exception_catalog'
17
- require 'exception_handling/exception_info'
18
- require 'exception_handling/escalate_callback'
10
+ require "exception_handling/mailer"
11
+ require "exception_handling/sensu"
12
+ require "exception_handling/methods"
13
+ require "exception_handling/log_stub_error"
14
+ require "exception_handling/exception_description"
15
+ require "exception_handling/exception_catalog"
16
+ require "exception_handling/exception_info"
17
+ require "exception_handling/honeybadger_callbacks.rb"
19
18
 
20
19
  _ = ActiveSupport::HashWithIndifferentAccess
21
20
 
@@ -30,8 +29,6 @@ module ExceptionHandling # never included
30
29
  AUTHENTICATION_HEADERS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION', 'REDIRECT_X_HTTP_AUTHORIZATION'].freeze
31
30
  HONEYBADGER_STATUSES = [:success, :failure, :skipped].freeze
32
31
 
33
- Deprecation3_0 = ActiveSupport::Deprecation.new('3.0', 'exception_handling')
34
-
35
32
  class << self
36
33
 
37
34
  #
@@ -53,22 +50,12 @@ module ExceptionHandling # never included
53
50
  @exception_recipients or raise ArgumentError, "You must assign a value to #{name}.exception_recipients"
54
51
  end
55
52
 
56
- def configured?
57
- !@logger.nil?
58
- end
59
-
60
53
  def logger
61
54
  @logger or raise ArgumentError, "You must assign a value to #{name}.logger"
62
55
  end
63
56
 
64
57
  def logger=(logger)
65
- @logger = if logger.nil? || logger.is_a?(ContextualLogger::LoggerMixin)
66
- logger
67
- else
68
- Deprecation3_0.deprecation_warning('implicit extend with ContextualLogger::LoggerMixin', 'extend your logger instance or include into your logger class first')
69
- logger.extend(ContextualLogger::LoggerMixin)
70
- end
71
- EscalateCallback.register_if_configured!
58
+ @logger = logger.is_a?(ContextualLogger) ? logger : ContextualLogger.new(logger)
72
59
  end
73
60
 
74
61
  def default_metric_name(exception_data, exception, treat_like_warning)
@@ -190,18 +177,13 @@ module ExceptionHandling # never included
190
177
  # Called directly by our code, usually from rescue blocks.
191
178
  # Writes to log file and may send to honeybadger
192
179
  #
193
- # TODO: the **log_context means we can never have context named treat_like_warning. In general, keyword args will be conflated with log_context.
194
- # Ideally we'd separate to log_context from the other keywords so they don't interfere in any way. Or have no keyword args.
195
- #
196
180
  # Functional Test Operation:
197
181
  # Calls into handle_stub_log_error and returns. no log file. no honeybadger
198
182
  #
199
- def log_error(exception_or_string, exception_context = '', controller = nil, treat_like_warning: false, **log_context, &data_callback)
183
+ def log_error(exception_or_string, exception_context = '', treat_like_warning: false, **log_context, &data_callback)
200
184
  ex = make_exception(exception_or_string)
201
185
  timestamp = set_log_error_timestamp
202
- exception_info = ExceptionInfo.new(ex, exception_context, timestamp,
203
- controller: controller || current_controller, data_callback: data_callback,
204
- log_context: log_context)
186
+ exception_info = ExceptionInfo.new(ex, exception_context, timestamp, current_controller, data_callback)
205
187
 
206
188
  if stub_handler
207
189
  stub_handler.handle_stub_log_error(exception_info.data)
@@ -228,13 +210,7 @@ module ExceptionHandling # never included
228
210
  #
229
211
  def write_exception_to_log(ex, exception_context, timestamp, log_context = {})
230
212
  ActiveSupport::Deprecation.silence do
231
- log_message = "#{exception_context}\n#{ex.class}: (#{encode_utf8(ex.message.to_s)}):\n " + clean_backtrace(ex).join("\n ") + "\n\n"
232
-
233
- if ex.is_a?(Warning)
234
- ExceptionHandling.logger.warn("\nExceptionHandlingWarning (Warning:#{timestamp}) #{log_message}", **log_context)
235
- else
236
- ExceptionHandling.logger.fatal("\nExceptionHandlingError (Error:#{timestamp}) #{log_message}", **log_context)
237
- end
213
+ ExceptionHandling.logger.fatal("\nExceptionHandlingError (Error:#{timestamp}) #{ex.class} #{exception_context} (#{encode_utf8(ex.message.to_s)}):\n " + clean_backtrace(ex).join("\n ") + "\n\n", log_context)
238
214
  end
239
215
  end
240
216
 
@@ -289,8 +265,9 @@ module ExceptionHandling # never included
289
265
  #
290
266
  # Expects passed in hash to only include keys which be directly set on the Honeybadger config
291
267
  #
292
- def enable_honeybadger(**config)
268
+ def enable_honeybadger(config = {})
293
269
  Bundler.require(:honeybadger)
270
+ HoneybadgerCallbacks.register_callbacks
294
271
  Honeybadger.configure do |config_klass|
295
272
  config.each do |k, v|
296
273
  config_klass.send(:"#{k}=", v)
@@ -298,28 +275,28 @@ module ExceptionHandling # never included
298
275
  end
299
276
  end
300
277
 
301
- def log_warning(message, **log_context)
278
+ def log_warning(message, log_context = {})
302
279
  warning = Warning.new(message)
303
280
  warning.set_backtrace([])
304
281
  log_error(warning, **log_context)
305
282
  end
306
283
 
307
- def log_info(message, **log_context)
308
- ExceptionHandling.logger.info(message, **log_context)
284
+ def log_info(message, log_context = {})
285
+ ExceptionHandling.logger.info(message, log_context)
309
286
  end
310
287
 
311
- def log_debug(message, **log_context)
312
- ExceptionHandling.logger.debug(message, **log_context)
288
+ def log_debug(message, log_context = {})
289
+ ExceptionHandling.logger.debug(message, log_context)
313
290
  end
314
291
 
315
- def ensure_safe(exception_context = "", **log_context)
292
+ def ensure_safe(exception_context = "", log_context = {})
316
293
  yield
317
294
  rescue => ex
318
295
  log_error(ex, exception_context, **log_context)
319
296
  nil
320
297
  end
321
298
 
322
- def ensure_completely_safe(exception_context = "", **log_context)
299
+ def ensure_completely_safe(exception_context = "", log_context = {})
323
300
  yield
324
301
  rescue SystemExit, SystemStackError, NoMemoryError, SecurityError, SignalException
325
302
  raise
@@ -334,29 +311,26 @@ module ExceptionHandling # never included
334
311
  escalate(email_subject, ex, last_exception_timestamp, production_support_recipients)
335
312
  end
336
313
 
337
- def escalate_error(exception_or_string, email_subject, custom_recipients = nil, **log_context)
314
+ def escalate_error(exception_or_string, email_subject, custom_recipients = nil, log_context = {})
338
315
  ex = make_exception(exception_or_string)
339
316
  log_error(ex, **log_context)
340
317
  escalate(email_subject, ex, last_exception_timestamp, custom_recipients)
341
318
  end
342
319
 
343
- def escalate_warning(message, email_subject, custom_recipients = nil, **log_context)
320
+ def escalate_warning(message, email_subject, custom_recipients = nil, log_context = {})
344
321
  ex = Warning.new(message)
345
322
  log_error(ex, **log_context)
346
323
  escalate(email_subject, ex, last_exception_timestamp, custom_recipients)
347
324
  end
348
325
 
349
- def ensure_escalation(email_subject, custom_recipients = nil, **log_context)
326
+ def ensure_escalation(email_subject, custom_recipients = nil, log_context = {})
350
327
  yield
351
328
  rescue => ex
352
- escalate_error(ex, email_subject, custom_recipients, **log_context)
329
+ escalate_error(ex, email_subject, custom_recipients, log_context)
353
330
  nil
354
331
  end
355
332
 
356
- deprecate :escalate_to_production_support, :escalate_error, :escalate_warning, :ensure_escalation,
357
- deprecator: ActiveSupport::Deprecation.new('3.0', 'ExceptionHandling')
358
-
359
- def alert_warning(exception_or_string, alert_name, exception_context, **log_context)
333
+ def alert_warning(exception_or_string, alert_name, exception_context, log_context)
360
334
  ex = make_exception(exception_or_string)
361
335
  log_error(ex, exception_context, **log_context)
362
336
  begin
@@ -366,10 +340,10 @@ module ExceptionHandling # never included
366
340
  end
367
341
  end
368
342
 
369
- def ensure_alert(alert_name, exception_context, **log_context)
343
+ def ensure_alert(alert_name, exception_context, log_context = {})
370
344
  yield
371
345
  rescue => ex
372
- alert_warning(ex, alert_name, exception_context, **log_context)
346
+ alert_warning(ex, alert_name, exception_context, log_context)
373
347
  nil
374
348
  end
375
349
 
@@ -386,7 +360,7 @@ module ExceptionHandling # never included
386
360
  result
387
361
  end
388
362
 
389
- def log_periodically(exception_key, interval, message, **log_context)
363
+ def log_periodically(exception_key, interval, message, log_context = {})
390
364
  self.periodic_exception_intervals ||= {}
391
365
  last_logged = self.periodic_exception_intervals[exception_key]
392
366
  if !last_logged || ((last_logged + interval) < Time.now)
@@ -489,6 +463,4 @@ module ExceptionHandling # never included
489
463
  end
490
464
  end
491
465
  end
492
-
493
- EscalateCallback.register_if_configured!
494
466
  end
@@ -0,0 +1,3 @@
1
+ #!/bin/sh -x
2
+
3
+ bundle install --path vendor/bundle
File without changes
@@ -7,7 +7,7 @@ module ExceptionHelpers
7
7
 
8
8
  def exception_with_nil_message
9
9
  exception_with_nil_message = RuntimeError.new(nil)
10
- allow(exception_with_nil_message).to receive(:message).and_return(nil)
10
+ stub(exception_with_nil_message).message { nil }
11
11
  exception_with_nil_message
12
12
  end
13
13
 
@@ -15,6 +15,6 @@ module ExceptionHelpers
15
15
 
16
16
  def capture_notifications
17
17
  @sent_notifications = []
18
- allow(ExceptionHandling).to receive(:send_exception_to_honeybadger).with(any_args) { |exception_info| @sent_notifications << exception_info }
18
+ stub(ExceptionHandling).send_exception_to_honeybadger(anything) { |exception_info| @sent_notifications << exception_info }
19
19
  end
20
20
  end
@@ -1,9 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rspec'
4
- require 'rspec/mocks'
5
- require 'rspec_junit_formatter'
6
-
3
+ require 'active_support'
4
+ require 'active_support/time'
5
+ require 'active_support/test_case'
6
+ require 'active_model'
7
+ require 'action_mailer'
8
+ require 'action_dispatch'
9
+ require 'hobo_support'
10
+ require 'shoulda'
11
+ require 'rr'
12
+ require 'minitest/autorun'
7
13
  require 'pry'
8
14
  require 'honeybadger'
9
15
  require 'contextual_logger'
@@ -11,31 +17,26 @@ require 'contextual_logger'
11
17
  require 'exception_handling'
12
18
  require 'exception_handling/testing'
13
19
 
20
+ ActiveSupport::TestCase.test_order = :sorted
21
+
14
22
  class LoggerStub
15
- include ContextualLogger::LoggerMixin
16
- attr_accessor :logged, :level
23
+ include ContextualLogger
24
+ attr_accessor :logged
17
25
 
18
26
  def initialize
19
- @level = Logger::Severity::DEBUG
20
- @progname = nil
21
- @logdev = nil
22
27
  clear
23
28
  end
24
29
 
25
- def debug(message, log_context = {})
26
- logged << { message: message, context: log_context, severity: 'DEBUG' }
27
- end
28
-
29
30
  def info(message, log_context = {})
30
- logged << { message: message, context: log_context, severity: 'INFO' }
31
+ logged << { message: message, context: log_context }
31
32
  end
32
33
 
33
34
  def warn(message, log_context = {})
34
- logged << { message: message, context: log_context, severity: 'WARN' }
35
+ logged << { message: message, context: log_context }
35
36
  end
36
37
 
37
38
  def fatal(message, log_context = {})
38
- logged << { message: message, context: log_context, severity: 'FATAL' }
39
+ logged << { message: message, context: log_context }
39
40
  end
40
41
 
41
42
  def clear
@@ -76,17 +77,27 @@ end
76
77
 
77
78
  ActionMailer::Base.delivery_method = :test
78
79
 
80
+ _ = ActiveSupport
81
+ _ = ActiveSupport::TestCase
79
82
 
80
- module TestHelper
81
- @constant_overrides = []
82
- class << self
83
- attr_accessor :constant_overrides
84
- end
83
+ class ActiveSupport::TestCase
84
+ @@constant_overrides = []
85
+
86
+ setup do
87
+ unless @@constant_overrides.nil? || @@constant_overrides.empty?
88
+ raise "Uh-oh! constant_overrides left over: #{@@constant_overrides.inspect}"
89
+ end
85
90
 
91
+ unless defined?(Rails) && defined?(Rails.env)
92
+ module ::Rails
93
+ class << self
94
+ attr_writer :env
86
95
 
87
- def setup_constant_overrides
88
- unless TestHelper.constant_overrides.nil? || TestHelper.constant_overrides.empty?
89
- raise "Uh-oh! constant_overrides left over: #{TestHelper.constant_overrides.inspect}"
96
+ def env
97
+ @env ||= 'test'
98
+ end
99
+ end
100
+ end
90
101
  end
91
102
 
92
103
  Time.now_override = nil
@@ -106,8 +117,8 @@ module TestHelper
106
117
  ExceptionHandling.sensu_prefix = ""
107
118
  end
108
119
 
109
- def teardown_constant_overrides
110
- TestHelper.constant_overrides&.reverse&.each do |parent_module, k, v|
120
+ teardown do
121
+ @@constant_overrides&.reverse&.each do |parent_module, k, v|
111
122
  ExceptionHandling.ensure_safe "constant cleanup #{k.inspect}, #{parent_module}(#{parent_module.class})::#{v.inspect}(#{v.class})" do
112
123
  silence_warnings do
113
124
  if v == :never_defined
@@ -118,7 +129,7 @@ module TestHelper
118
129
  end
119
130
  end
120
131
  end
121
- TestHelper.constant_overrides = []
132
+ @@constant_overrides = []
122
133
  end
123
134
 
124
135
  def set_test_const(const_name, value)
@@ -138,7 +149,7 @@ module TestHelper
138
149
  end
139
150
  end
140
151
 
141
- TestHelper.constant_overrides << [final_parent_module, final_const_name, original_value]
152
+ @@constant_overrides << [final_parent_module, final_const_name, original_value]
142
153
 
143
154
  silence_warnings { final_parent_module.const_set(final_const_name, value) }
144
155
  end
@@ -150,15 +161,15 @@ module TestHelper
150
161
  else
151
162
  original_count = 0
152
163
  end
153
- expect(ActionMailer::Base.deliveries.size - original_count).to eq(expected), "wrong number of emails#{': ' + message.to_s if message}"
164
+ assert_equal expected, ActionMailer::Base.deliveries.size - original_count, "wrong number of emails#{': ' + message.to_s if message}"
154
165
  end
155
166
  end
156
167
 
157
168
  def assert_equal_with_diff(arg1, arg2, msg = '')
158
169
  if arg1 == arg2
159
- expect(true).to be_truthy # To keep the assertion count accurate
170
+ assert true # To keep the assertion count accurate
160
171
  else
161
- expect(arg1).to eq(arg2), "#{msg}\n#{Diff.compare(arg1, arg2)}"
172
+ assert_equal arg1, arg2, "#{msg}\n#{Diff.compare(arg1, arg2)}"
162
173
  end
163
174
  end
164
175
 
@@ -189,35 +200,3 @@ class Time
189
200
  end
190
201
  end
191
202
  end
192
-
193
- RSpec.configure do |config|
194
- config.add_formatter(RspecJunitFormatter, 'spec/reports/rspec.xml')
195
- config.include TestHelper
196
-
197
- config.before(:each) do
198
- setup_constant_overrides
199
- unless defined?(Rails) && defined?(Rails.env)
200
- module Rails
201
- class << self
202
- attr_writer :env
203
-
204
- def env
205
- @env ||= 'test'
206
- end
207
- end
208
- end
209
- end
210
- end
211
-
212
- config.after(:each) do
213
- teardown_constant_overrides
214
- end
215
-
216
- config.mock_with :rspec do |mocks|
217
- mocks.verify_partial_doubles = true
218
- end
219
-
220
- config.expect_with(:rspec, :test_unit)
221
-
222
- RSpec::Support::ObjectFormatter.default_instance.max_formatted_output_length = 2_000
223
- end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../../test_helper', __dir__)
4
+
5
+ module ExceptionHandling
6
+ class ExceptionCatalogTest < ActiveSupport::TestCase
7
+
8
+ context "With stubbed yaml content" do
9
+ setup do
10
+ filter_list = { exception1: { error: "my error message" },
11
+ exception2: { error: "some other message", session: "misc data" } }
12
+ stub(YAML).load_file { filter_list }
13
+
14
+ # bump modified time up to get the above filter loaded
15
+ stub(File).mtime { incrementing_mtime }
16
+ end
17
+
18
+ context "with loaded data" do
19
+ setup do
20
+ stub(File).mtime { incrementing_mtime }
21
+ @exception_catalog = ExceptionCatalog.new(ExceptionHandling.filter_list_filename)
22
+ @exception_catalog.send :load_file
23
+ end
24
+
25
+ should "have loaded filters" do
26
+ assert_equal 2, @exception_catalog.instance_eval("@filters").size
27
+ end
28
+
29
+ should "find messages in the catalog" do
30
+ assert !@exception_catalog.find(error: "Scott says unlikely to ever match")
31
+ end
32
+
33
+ should "find matching data" do
34
+ exception_description = @exception_catalog.find(error: "this is my error message, which should match something")
35
+ assert exception_description
36
+ assert_equal :exception1, exception_description.filter_name
37
+ end
38
+ end
39
+
40
+ should "write errors loading the yaml file directly to the log file" do
41
+ @exception_catalog = ExceptionCatalog.new(ExceptionHandling.filter_list_filename)
42
+
43
+ mock(ExceptionHandling).log_error.never
44
+ mock(ExceptionHandling).write_exception_to_log(anything, "ExceptionCatalog#refresh_filters: ./config/exception_filters.yml", anything)
45
+ mock(@exception_catalog).load_file { raise "noooooo" }
46
+
47
+ @exception_catalog.find({})
48
+ end
49
+ end
50
+
51
+ context "with live yaml content" do
52
+ setup do
53
+ @filename = File.expand_path('../../../config/exception_filters.yml', __dir__)
54
+ @exception_catalog = ExceptionCatalog.new(@filename)
55
+ assert_nothing_raised "Loading the exception filter should not raise" do
56
+ @exception_catalog.send :load_file
57
+ end
58
+ end
59
+
60
+ should "load the filter data" do
61
+ assert !@exception_catalog.find(error: "Scott says unlikely to ever match")
62
+ assert !@exception_catalog.find(error: "Scott says unlikely to ever match")
63
+ end
64
+ end
65
+
66
+ context "with no yaml content" do
67
+ setup do
68
+ @exception_catalog = ExceptionCatalog.new(nil)
69
+ end
70
+
71
+ should "not load filter data" do
72
+ mock(ExceptionHandling).write_exception_to_log.with_any_args.never
73
+ @exception_catalog.find(error: "Scott says unlikely to ever match")
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ def incrementing_mtime
80
+ @mtime ||= Time.now
81
+ @mtime += 1.day
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../../test_helper', __dir__)
4
+
5
+ module ExceptionHandling
6
+ class ExceptionDescriptionTest < ActiveSupport::TestCase
7
+
8
+ context "Filter" do
9
+ should "allow direct matching of strings" do
10
+ @f = ExceptionDescription.new(:filter1, error: "my error message")
11
+ assert @f.match?('error' => "my error message")
12
+ end
13
+
14
+ should "allow direct matching of strings on with symbol keys" do
15
+ @f = ExceptionDescription.new(:filter1, error: "my error message")
16
+ assert @f.match?(error: "my error message")
17
+ end
18
+
19
+ should "allow wildcards to cross line boundries" do
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")
22
+ end
23
+
24
+ should "complain when no regexps have a value" do
25
+ assert_raise(ArgumentError, "has all blank regexe") { ExceptionDescription.new(:filter1, error: nil) }
26
+ end
27
+
28
+ should "report when an invalid key is passed" do
29
+ assert_raise(ArgumentError, "Unknown section: not_a_parameter") { ExceptionDescription.new(:filter1, error: "my error message", not_a_parameter: false) }
30
+ end
31
+
32
+ should "allow send_to_honeybadger to be specified and have it disabled by default" do
33
+ assert !ExceptionDescription.new(:filter1, error: "my error message", send_to_honeybadger: false).send_to_honeybadger
34
+ assert ExceptionDescription.new(:filter1, error: "my error message", send_to_honeybadger: true).send_to_honeybadger
35
+ assert !ExceptionDescription.new(:filter1, error: "my error message").send_to_honeybadger
36
+ end
37
+
38
+ should "allow send_metric to be configured" do
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
41
+ end
42
+
43
+ should "provide metric name" do
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
46
+ end
47
+
48
+ should "replace spaces in metric name" do
49
+ @f = ExceptionDescription.new(:"filter has spaces", error: "my error message")
50
+ assert_equal "filter_has_spaces", @f.metric_name
51
+ end
52
+
53
+ should "allow notes to be recorded" do
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
56
+ end
57
+
58
+ should "not consider config options in the filter set" do
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")
62
+ end
63
+
64
+ should "provide exception details" do
65
+ exception_description = ExceptionDescription.new(:filter1, error: "my error message", notes: "hey")
66
+
67
+ expected = { "send_metric" => true, "metric_name" => "filter1", "notes" => "hey" }
68
+
69
+ assert_equal expected, exception_description.exception_data
70
+ end
71
+
72
+ should "match multiple email addresses" do
73
+ mobi = "ExceptionHandling::Warning: LoginAttempt::IPAddressLocked: failed login for 'mcc@mobistreak.com'"
74
+ credit = "ExceptionHandling::Warning: LoginAttempt::IPAddressLocked: failed login for 'damon@thecreditpros.com'"
75
+
76
+ exception_description = ExceptionDescription.new(:filter1, error: "ExceptionHandling::Warning: LoginAttempt::IPAddressLocked: failed login for '(mcc\@mobistreak|damon\@thecreditpros).com'")
77
+ assert exception_description.match?(error: mobi), "does not match mobi"
78
+ assert exception_description.match?(error: credit), "does not match credit"
79
+ end
80
+ end
81
+ end
82
+ end