exception_handling 3.0.pre.1 → 3.0.0.pre.2

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