bugsnag 4.2.1 → 6.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. checksums.yaml +5 -5
  2. data/.yardopts +12 -0
  3. data/CHANGELOG.md +814 -0
  4. data/README.md +21 -25
  5. data/VERSION +1 -1
  6. data/bugsnag.gemspec +19 -8
  7. data/lib/bugsnag/breadcrumb_type.rb +14 -0
  8. data/lib/bugsnag/breadcrumbs/breadcrumb.rb +109 -0
  9. data/lib/bugsnag/breadcrumbs/breadcrumbs.rb +13 -0
  10. data/lib/bugsnag/breadcrumbs/on_breadcrumb_callback_list.rb +48 -0
  11. data/lib/bugsnag/breadcrumbs/validator.rb +29 -0
  12. data/lib/bugsnag/cleaner.rb +170 -59
  13. data/lib/bugsnag/code_extractor.rb +137 -0
  14. data/lib/bugsnag/configuration.rb +670 -45
  15. data/lib/bugsnag/delivery/synchronous.rb +31 -14
  16. data/lib/bugsnag/delivery/thread_queue.rb +23 -6
  17. data/lib/bugsnag/delivery.rb +13 -0
  18. data/lib/bugsnag/endpoint_configuration.rb +11 -0
  19. data/lib/bugsnag/endpoint_validator.rb +80 -0
  20. data/lib/bugsnag/error.rb +25 -0
  21. data/lib/bugsnag/event.rb +5 -0
  22. data/lib/bugsnag/feature_flag.rb +74 -0
  23. data/lib/bugsnag/helpers.rb +121 -25
  24. data/lib/bugsnag/integrations/delayed_job.rb +51 -0
  25. data/lib/bugsnag/integrations/mailman.rb +43 -0
  26. data/lib/bugsnag/integrations/mongo.rb +133 -0
  27. data/lib/bugsnag/integrations/que.rb +53 -0
  28. data/lib/bugsnag/integrations/rack.rb +83 -0
  29. data/lib/bugsnag/integrations/rails/active_job.rb +100 -0
  30. data/lib/bugsnag/{rails → integrations/rails}/active_record_rescue.rb +10 -1
  31. data/lib/bugsnag/{rails → integrations/rails}/controller_methods.rb +1 -9
  32. data/lib/bugsnag/integrations/rails/rails_breadcrumbs.rb +115 -0
  33. data/lib/bugsnag/integrations/railtie.rb +153 -0
  34. data/lib/bugsnag/integrations/rake.rb +74 -0
  35. data/lib/bugsnag/integrations/resque.rb +94 -0
  36. data/lib/bugsnag/integrations/shoryuken.rb +50 -0
  37. data/lib/bugsnag/integrations/sidekiq.rb +68 -0
  38. data/lib/bugsnag/meta_data.rb +1 -0
  39. data/lib/bugsnag/middleware/active_job.rb +18 -0
  40. data/lib/bugsnag/middleware/breadcrumbs.rb +21 -0
  41. data/lib/bugsnag/middleware/callbacks.rb +6 -8
  42. data/lib/bugsnag/middleware/classify_error.rb +50 -0
  43. data/lib/bugsnag/middleware/clearance_user.rb +33 -0
  44. data/lib/bugsnag/middleware/delayed_job.rb +93 -0
  45. data/lib/bugsnag/middleware/discard_error_class.rb +30 -0
  46. data/lib/bugsnag/middleware/exception_meta_data.rb +42 -0
  47. data/lib/bugsnag/middleware/ignore_error_class.rb +26 -0
  48. data/lib/bugsnag/middleware/mailman.rb +6 -4
  49. data/lib/bugsnag/middleware/rack_request.rb +126 -30
  50. data/lib/bugsnag/middleware/rails3_request.rb +15 -17
  51. data/lib/bugsnag/middleware/rake.rb +7 -5
  52. data/lib/bugsnag/middleware/session_data.rb +25 -0
  53. data/lib/bugsnag/middleware/sidekiq.rb +9 -4
  54. data/lib/bugsnag/middleware/suggestion_data.rb +34 -0
  55. data/lib/bugsnag/middleware/warden_user.rb +11 -6
  56. data/lib/bugsnag/middleware_stack.rb +62 -9
  57. data/lib/bugsnag/on_error_callbacks.rb +33 -0
  58. data/lib/bugsnag/report.rb +516 -0
  59. data/lib/bugsnag/session_tracker.rb +182 -0
  60. data/lib/bugsnag/stacktrace.rb +82 -0
  61. data/lib/bugsnag/tasks/bugsnag.rake +2 -70
  62. data/lib/bugsnag/utility/circular_buffer.rb +62 -0
  63. data/lib/bugsnag/utility/duplicator.rb +124 -0
  64. data/lib/bugsnag/utility/feature_data_store.rb +41 -0
  65. data/lib/bugsnag/utility/feature_flag_delegate.rb +89 -0
  66. data/lib/bugsnag/utility/metadata_delegate.rb +102 -0
  67. data/lib/bugsnag.rb +528 -80
  68. metadata +61 -123
  69. data/.document +0 -5
  70. data/.gitignore +0 -52
  71. data/.rspec +0 -3
  72. data/.travis.yml +0 -14
  73. data/CONTRIBUTING.md +0 -47
  74. data/Gemfile +0 -2
  75. data/Rakefile +0 -29
  76. data/lib/bugsnag/capistrano.rb +0 -7
  77. data/lib/bugsnag/capistrano2.rb +0 -32
  78. data/lib/bugsnag/delay/resque.rb +0 -21
  79. data/lib/bugsnag/delayed_job.rb +0 -57
  80. data/lib/bugsnag/deploy.rb +0 -34
  81. data/lib/bugsnag/mailman.rb +0 -28
  82. data/lib/bugsnag/middleware/rails2_request.rb +0 -52
  83. data/lib/bugsnag/notification.rb +0 -459
  84. data/lib/bugsnag/rack.rb +0 -53
  85. data/lib/bugsnag/rails/action_controller_rescue.rb +0 -62
  86. data/lib/bugsnag/rails.rb +0 -66
  87. data/lib/bugsnag/railtie.rb +0 -80
  88. data/lib/bugsnag/rake.rb +0 -25
  89. data/lib/bugsnag/resque.rb +0 -40
  90. data/lib/bugsnag/sidekiq.rb +0 -42
  91. data/lib/bugsnag/tasks/bugsnag.cap +0 -48
  92. data/rails/init.rb +0 -7
  93. data/spec/cleaner_spec.rb +0 -138
  94. data/spec/code_spec.rb +0 -86
  95. data/spec/fixtures/crashes/end_of_file.rb +0 -9
  96. data/spec/fixtures/crashes/short_file.rb +0 -1
  97. data/spec/fixtures/crashes/start_of_file.rb +0 -9
  98. data/spec/fixtures/middleware/internal_info_setter.rb +0 -11
  99. data/spec/fixtures/middleware/public_info_setter.rb +0 -11
  100. data/spec/fixtures/tasks/Rakefile +0 -15
  101. data/spec/helper_spec.rb +0 -163
  102. data/spec/integration_spec.rb +0 -132
  103. data/spec/middleware_spec.rb +0 -181
  104. data/spec/notification_spec.rb +0 -877
  105. data/spec/rack_spec.rb +0 -56
  106. data/spec/spec_helper.rb +0 -53
@@ -1,877 +0,0 @@
1
- # encoding: utf-8
2
- require 'spec_helper'
3
- require 'securerandom'
4
- require 'ostruct'
5
-
6
- module ActiveRecord; class RecordNotFound < RuntimeError; end; end
7
- class NestedException < StandardError; attr_accessor :original_exception; end
8
- class BugsnagTestExceptionWithMetaData < Exception; include Bugsnag::MetaData; end
9
- class BugsnagSubclassTestException < BugsnagTestException; end
10
-
11
- class Ruby21Exception < RuntimeError
12
- attr_accessor :cause
13
- def self.raise!(msg)
14
- e = new(msg)
15
- e.cause = $!
16
- raise e
17
- end
18
- end
19
-
20
- class JRubyException
21
- def self.raise!
22
- new.gloops
23
- end
24
-
25
- def gloops
26
- java.lang.System.out.printf(nil)
27
- end
28
- end
29
-
30
- describe Bugsnag::Notification do
31
- it "should contain an api_key if one is set" do
32
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
33
-
34
- expect(Bugsnag).to have_sent_notification{ |payload|
35
- expect(payload["apiKey"]).to eq("c9d60ae4c7e70c4b6c4ebd3e8056d2b8")
36
- }
37
- end
38
-
39
- it "does not notify if api_key is not set" do
40
- Bugsnag.configuration.api_key = nil
41
-
42
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
43
-
44
- expect(Bugsnag).not_to have_sent_notification
45
- end
46
-
47
- it "does not notify if api_key is empty" do
48
- Bugsnag.configuration.api_key = ""
49
-
50
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
51
-
52
- expect(Bugsnag).not_to have_sent_notification
53
- end
54
-
55
- it "lets you override the api_key" do
56
- Bugsnag.notify(BugsnagTestException.new("It crashed"), :api_key => "9d84383f9be2ca94902e45c756a9979d")
57
-
58
- expect(Bugsnag).to have_sent_notification{ |payload|
59
- expect(payload["apiKey"]).to eq("9d84383f9be2ca94902e45c756a9979d")
60
- }
61
- end
62
-
63
- it "lets you override the groupingHash" do
64
-
65
- Bugsnag.notify(BugsnagTestException.new("It crashed"), {:grouping_hash => "this is my grouping hash"})
66
-
67
- expect(Bugsnag).to have_sent_notification{ |payload|
68
- event = get_event_from_payload(payload)
69
- expect(event["groupingHash"]).to eq("this is my grouping hash")
70
- }
71
- end
72
-
73
- it "uses the env variable apiKey" do
74
- ENV["BUGSNAG_API_KEY"] = "c9d60ae4c7e70c4b6c4ebd3e8056d2b9"
75
-
76
- Bugsnag.instance_variable_set(:@configuration, Bugsnag::Configuration.new)
77
- Bugsnag.configure do |config|
78
- config.release_stage = "production"
79
- config.delivery_method = :synchronous
80
- end
81
-
82
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
83
-
84
- expect(Bugsnag).to have_sent_notification{ |payload|
85
- expect(payload["apiKey"]).to eq("c9d60ae4c7e70c4b6c4ebd3e8056d2b9")
86
- }
87
- end
88
-
89
- it "has the right exception class" do
90
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
91
-
92
- expect(Bugsnag).to have_sent_notification{ |payload|
93
- exception = get_exception_from_payload(payload)
94
- expect(exception["errorClass"]).to eq("BugsnagTestException")
95
- }
96
- end
97
-
98
- it "has the right exception message" do
99
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
100
-
101
- expect(Bugsnag).to have_sent_notification{ |payload|
102
- exception = get_exception_from_payload(payload)
103
- expect(exception["message"]).to eq("It crashed")
104
- }
105
- end
106
-
107
- it "has a valid stacktrace" do
108
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
109
-
110
- expect(Bugsnag).to have_sent_notification{ |payload|
111
- exception = get_exception_from_payload(payload)
112
- expect(exception["stacktrace"].length).to be > 0
113
- }
114
- end
115
-
116
- # TODO: nested context
117
-
118
- it "accepts tabs in overrides and adds them to metaData" do
119
- Bugsnag.notify(BugsnagTestException.new("It crashed"), {
120
- :some_tab => {
121
- :info => "here",
122
- :data => "also here"
123
- }
124
- })
125
-
126
- expect(Bugsnag).to have_sent_notification{ |payload|
127
- event = get_event_from_payload(payload)
128
- expect(event["metaData"]["some_tab"]).to eq(
129
- "info" => "here",
130
- "data" => "also here"
131
- )
132
- }
133
- end
134
-
135
- it "accepts non-hash overrides and adds them to the custom tab in metaData" do
136
- Bugsnag.notify(BugsnagTestException.new("It crashed"), {
137
- :info => "here",
138
- :data => "also here"
139
- })
140
-
141
- expect(Bugsnag).to have_sent_notification{ |payload|
142
- event = get_event_from_payload(payload)
143
- expect(event["metaData"]["custom"]).to eq(
144
- "info" => "here",
145
- "data" => "also here"
146
- )
147
- }
148
- end
149
-
150
- it "accepts meta data from an exception that mixes in Bugsnag::MetaData" do
151
- exception = BugsnagTestExceptionWithMetaData.new("It crashed")
152
- exception.bugsnag_meta_data = {
153
- :some_tab => {
154
- :info => "here",
155
- :data => "also here"
156
- }
157
- }
158
-
159
- Bugsnag.notify(exception)
160
-
161
- expect(Bugsnag).to have_sent_notification{ |payload|
162
- event = get_event_from_payload(payload)
163
- expect(event["metaData"]["some_tab"]).to eq(
164
- "info" => "here",
165
- "data" => "also here"
166
- )
167
- }
168
- end
169
-
170
- it "accepts meta data from an exception that mixes in Bugsnag::MetaData, but override using the overrides" do
171
- exception = BugsnagTestExceptionWithMetaData.new("It crashed")
172
- exception.bugsnag_meta_data = {
173
- :some_tab => {
174
- :info => "here",
175
- :data => "also here"
176
- }
177
- }
178
-
179
- Bugsnag.notify(exception, {:some_tab => {:info => "overridden"}})
180
-
181
- expect(Bugsnag).to have_sent_notification{ |payload|
182
- event = get_event_from_payload(payload)
183
- expect(event["metaData"]["some_tab"]).to eq(
184
- "info" => "overridden",
185
- "data" => "also here"
186
- )
187
- }
188
- end
189
-
190
- it "accepts user_id from an exception that mixes in Bugsnag::MetaData" do
191
- exception = BugsnagTestExceptionWithMetaData.new("It crashed")
192
- exception.bugsnag_user_id = "exception_user_id"
193
-
194
- Bugsnag.notify(exception)
195
-
196
- expect(Bugsnag).to have_sent_notification{ |payload|
197
- event = get_event_from_payload(payload)
198
- expect(event["user"]["id"]).to eq("exception_user_id")
199
- }
200
- end
201
-
202
- it "accepts user_id from an exception that mixes in Bugsnag::MetaData, but override using the overrides" do
203
- exception = BugsnagTestExceptionWithMetaData.new("It crashed")
204
- exception.bugsnag_user_id = "exception_user_id"
205
-
206
- Bugsnag.notify(exception, {:user_id => "override_user_id"})
207
-
208
- expect(Bugsnag).to have_sent_notification{ |payload|
209
- event = get_event_from_payload(payload)
210
- expect(event["user"]["id"]).to eq("override_user_id")
211
- }
212
- end
213
-
214
- it "accepts context from an exception that mixes in Bugsnag::MetaData" do
215
- exception = BugsnagTestExceptionWithMetaData.new("It crashed")
216
- exception.bugsnag_context = "exception_context"
217
-
218
- Bugsnag.notify(exception)
219
-
220
- expect(Bugsnag).to have_sent_notification{ |payload|
221
- event = get_event_from_payload(payload)
222
- expect(event["context"]).to eq("exception_context")
223
- }
224
- end
225
-
226
- it "accept contexts from an exception that mixes in Bugsnag::MetaData, but override using the overrides" do
227
-
228
- exception = BugsnagTestExceptionWithMetaData.new("It crashed")
229
- exception.bugsnag_context = "exception_context"
230
-
231
- Bugsnag.notify(exception, {:context => "override_context"})
232
-
233
- expect(Bugsnag).to have_sent_notification{ |payload|
234
- event = get_event_from_payload(payload)
235
- expect(event["context"]).to eq("override_context")
236
- }
237
- end
238
-
239
- it "accepts meta_data in overrides (for backwards compatibility) and merge it into metaData" do
240
- Bugsnag.notify(BugsnagTestException.new("It crashed"), {
241
- :meta_data => {
242
- :some_tab => {
243
- :info => "here",
244
- :data => "also here"
245
- }
246
- }
247
- })
248
-
249
- expect(Bugsnag).to have_sent_notification{ |payload|
250
- event = get_event_from_payload(payload)
251
- expect(event["metaData"]["some_tab"]).to eq(
252
- "info" => "here",
253
- "data" => "also here"
254
- )
255
- }
256
- end
257
-
258
- it "truncates large meta_data before sending" do
259
- Bugsnag.notify(BugsnagTestException.new("It crashed"), {
260
- :meta_data => {
261
- :some_tab => {
262
- :giant => SecureRandom.hex(500_000/2),
263
- :mega => SecureRandom.hex(500_000/2)
264
- }
265
- }
266
- })
267
-
268
- expect(Bugsnag).to have_sent_notification{ |payload|
269
- # Truncated body should be no bigger than
270
- # 2 truncated hashes (4096*2) + rest of payload (20000)
271
- expect(::JSON.dump(payload).length).to be < 4096*2 + 20000
272
- }
273
- end
274
-
275
- it "truncates large messages before sending" do
276
- Bugsnag.notify(BugsnagTestException.new(SecureRandom.hex(500_000)), {
277
- :meta_data => {
278
- :some_tab => {
279
- :giant => SecureRandom.hex(500_000/2),
280
- :mega => SecureRandom.hex(500_000/2)
281
- }
282
- }
283
- })
284
-
285
- expect(Bugsnag).to have_sent_notification{ |payload|
286
- # Truncated body should be no bigger than
287
- # 2 truncated hashes (4096*2) + rest of payload (20000)
288
- expect(::JSON.dump(payload).length).to be < 4096*2 + 20000
289
- }
290
- end
291
-
292
- it "truncate large stacktraces before sending" do
293
- ex = BugsnagTestException.new("It crashed")
294
- stacktrace = []
295
- 5000.times {|i| stacktrace.push("/Some/path/rspec/example.rb:113:in `instance_eval'")}
296
- ex.set_backtrace(stacktrace)
297
- Bugsnag.notify(ex)
298
-
299
- expect(Bugsnag).to have_sent_notification{ |payload|
300
- # Truncated body should be no bigger than
301
- # 400 stacktrace lines * approx 60 chars per line + rest of payload (20000)
302
- expect(::JSON.dump(payload).length).to be < 400*60 + 20000
303
- }
304
- end
305
-
306
- it "accepts a severity in overrides" do
307
- Bugsnag.notify(BugsnagTestException.new("It crashed"), {
308
- :severity => "info"
309
- })
310
-
311
- expect(Bugsnag).to have_sent_notification{ |payload|
312
- event = get_event_from_payload(payload)
313
- expect(event["severity"]).to eq("info")
314
- }
315
-
316
- end
317
-
318
- it "defaults to warning severity" do
319
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
320
-
321
- expect(Bugsnag).to have_sent_notification{ |payload|
322
- event = get_event_from_payload(payload)
323
- expect(event["severity"]).to eq("warning")
324
- }
325
- end
326
-
327
- it "does not accept a bad severity in overrides" do
328
- Bugsnag.notify(BugsnagTestException.new("It crashed"), {
329
- :severity => "fatal"
330
- })
331
-
332
- expect(Bugsnag).to have_sent_notification{ |payload|
333
- event = get_event_from_payload(payload)
334
- expect(event["severity"]).to eq("warning")
335
- }
336
- end
337
-
338
- it "lets you override severity using block syntax" do
339
- Bugsnag.notify(BugsnagTestException.new("It crashed")) do |notification|
340
- notification.severity = "info"
341
- end
342
-
343
- expect(Bugsnag).to have_sent_notification{ |payload|
344
- event = get_event_from_payload(payload)
345
- expect(event["severity"]).to eq("info")
346
- }
347
- end
348
-
349
- it "autonotifies errors" do
350
- Bugsnag.auto_notify(BugsnagTestException.new("It crashed"))
351
-
352
- expect(Bugsnag).to have_sent_notification{ |payload|
353
- event = get_event_from_payload(payload)
354
- expect(event["severity"]).to eq("error")
355
- }
356
- end
357
-
358
-
359
- it "accepts a context in overrides" do
360
- Bugsnag.notify(BugsnagTestException.new("It crashed"), {
361
- :context => "test_context"
362
- })
363
-
364
- expect(Bugsnag).to have_sent_notification{ |payload|
365
- event = get_event_from_payload(payload)
366
- expect(event["context"]).to eq("test_context")
367
- }
368
- end
369
-
370
- it "accepts a user_id in overrides" do
371
- Bugsnag.notify(BugsnagTestException.new("It crashed"), {
372
- :user_id => "test_user"
373
- })
374
-
375
- expect(Bugsnag).to have_sent_notification{ |payload|
376
- event = get_event_from_payload(payload)
377
- expect(event["user"]["id"]).to eq("test_user")
378
- }
379
- end
380
-
381
- it "does not send a notification if auto_notify is false" do
382
- Bugsnag.configure do |config|
383
- config.auto_notify = false
384
- end
385
-
386
- Bugsnag.auto_notify(BugsnagTestException.new("It crashed"))
387
-
388
- expect(Bugsnag).not_to have_sent_notification
389
- end
390
-
391
- it "contains a release_stage" do
392
- Bugsnag.configure do |config|
393
- config.release_stage = "production"
394
- end
395
-
396
- Bugsnag.auto_notify(BugsnagTestException.new("It crashed"))
397
-
398
- expect(Bugsnag).to have_sent_notification{ |payload|
399
- event = get_event_from_payload(payload)
400
- expect(event["app"]["releaseStage"]).to eq("production")
401
- }
402
- end
403
-
404
- it "respects the notify_release_stages setting by not sending in development" do
405
- Bugsnag.configuration.notify_release_stages = ["production"]
406
- Bugsnag.configuration.release_stage = "development"
407
-
408
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
409
-
410
- expect(Bugsnag).not_to have_sent_notification
411
- end
412
-
413
- it "respects the notify_release_stages setting when set" do
414
- Bugsnag.configuration.release_stage = "development"
415
- Bugsnag.configuration.notify_release_stages = ["development"]
416
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
417
-
418
- expect(Bugsnag).to have_sent_notification{ |payload|
419
- event = get_event_from_payload(payload)
420
- expect(event["exceptions"].length).to eq(1)
421
- }
422
- end
423
-
424
- it "uses the https://notify.bugsnag.com endpoint by default" do
425
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
426
-
427
- expect(WebMock).to have_requested(:post, "https://notify.bugsnag.com")
428
- end
429
-
430
- it "uses ssl when use_ssl is true" do
431
- Bugsnag.configuration.use_ssl = true
432
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
433
-
434
- expect(WebMock).to have_requested(:post, "https://notify.bugsnag.com")
435
- end
436
-
437
- it "does not use ssl when use_ssl is false" do
438
- stub_request(:post, "http://notify.bugsnag.com/")
439
- Bugsnag.configuration.use_ssl = false
440
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
441
-
442
- expect(WebMock).to have_requested(:post, "http://notify.bugsnag.com")
443
- end
444
-
445
- it "uses ssl when use_ssl is unset" do
446
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
447
-
448
- expect(WebMock).to have_requested(:post, "https://notify.bugsnag.com")
449
- end
450
-
451
- it "does not mark the top-most stacktrace line as inProject if out of project" do
452
- Bugsnag.configuration.project_root = "/Random/location/here"
453
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
454
-
455
- expect(Bugsnag).to have_sent_notification{ |payload|
456
- exception = get_exception_from_payload(payload)
457
- expect(exception["stacktrace"].size).to be >= 1
458
- expect(exception["stacktrace"].first["inProject"]).to be_nil
459
- }
460
- end
461
-
462
- it "does not mark the top-most stacktrace line as inProject if it matches a vendor path" do
463
- Bugsnag.configuration.project_root = File.expand_path('../../', __FILE__)
464
- Bugsnag.configuration.vendor_paths = [File.expand_path('../', __FILE__)]
465
-
466
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
467
-
468
- expect(Bugsnag).to have_sent_notification{ |payload|
469
- exception = get_exception_from_payload(payload)
470
- expect(exception["stacktrace"].size).to be >= 1
471
- expect(exception["stacktrace"].first["inProject"]).to be_nil
472
- }
473
- end
474
-
475
- it "marks the top-most stacktrace line as inProject if necessary" do
476
- Bugsnag.configuration.project_root = File.expand_path File.dirname(__FILE__)
477
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
478
-
479
- expect(Bugsnag).to have_sent_notification{ |payload|
480
- exception = get_exception_from_payload(payload)
481
- expect(exception["stacktrace"].size).to be >= 1
482
- expect(exception["stacktrace"].first["inProject"]).to eq(true)
483
- }
484
- end
485
-
486
- it "adds app_version to the payload if it is set" do
487
- Bugsnag.configuration.app_version = "1.1.1"
488
- Bugsnag.notify(BugsnagTestException.new("It crashed"))
489
-
490
- expect(Bugsnag).to have_sent_notification{ |payload|
491
- event = get_event_from_payload(payload)
492
- expect(event["app"]["version"]).to eq("1.1.1")
493
- }
494
- end
495
-
496
- it "filters params from all payload hashes if they are set in default params_filters" do
497
-
498
- Bugsnag.notify(BugsnagTestException.new("It crashed"), {:request => {:params => {:password => "1234", :other_password => "12345", :other_data => "123456"}}})
499
-
500
- expect(Bugsnag).to have_sent_notification{ |payload|
501
- event = get_event_from_payload(payload)
502
- expect(event["metaData"]).not_to be_nil
503
- expect(event["metaData"]["request"]).not_to be_nil
504
- expect(event["metaData"]["request"]["params"]).not_to be_nil
505
- expect(event["metaData"]["request"]["params"]["password"]).to eq("[FILTERED]")
506
- expect(event["metaData"]["request"]["params"]["other_password"]).to eq("[FILTERED]")
507
- expect(event["metaData"]["request"]["params"]["other_data"]).to eq("123456")
508
- }
509
- end
510
-
511
- it "filters params from all payload hashes if they are added to params_filters" do
512
-
513
- Bugsnag.configuration.params_filters << "other_data"
514
- Bugsnag.notify(BugsnagTestException.new("It crashed"), {:request => {:params => {:password => "1234", :other_password => "123456", :other_data => "123456"}}})
515
-
516
- expect(Bugsnag).to have_sent_notification{ |payload|
517
- event = get_event_from_payload(payload)
518
- expect(event["metaData"]).not_to be_nil
519
- expect(event["metaData"]["request"]).not_to be_nil
520
- expect(event["metaData"]["request"]["params"]).not_to be_nil
521
- expect(event["metaData"]["request"]["params"]["password"]).to eq("[FILTERED]")
522
- expect(event["metaData"]["request"]["params"]["other_password"]).to eq("[FILTERED]")
523
- expect(event["metaData"]["request"]["params"]["other_data"]).to eq("[FILTERED]")
524
- }
525
- end
526
-
527
- it "filters params from all payload hashes if they are added to params_filters as regex" do
528
-
529
- Bugsnag.configuration.params_filters << /other_data/
530
- Bugsnag.notify(BugsnagTestException.new("It crashed"), {:request => {:params => {:password => "1234", :other_password => "123456", :other_data => "123456"}}})
531
-
532
- expect(Bugsnag).to have_sent_notification{ |payload|
533
- event = get_event_from_payload(payload)
534
- expect(event["metaData"]).not_to be_nil
535
- expect(event["metaData"]["request"]).not_to be_nil
536
- expect(event["metaData"]["request"]["params"]).not_to be_nil
537
- expect(event["metaData"]["request"]["params"]["password"]).to eq("[FILTERED]")
538
- expect(event["metaData"]["request"]["params"]["other_password"]).to eq("[FILTERED]")
539
- expect(event["metaData"]["request"]["params"]["other_data"]).to eq("[FILTERED]")
540
- }
541
- end
542
-
543
- it "filters params from all payload hashes if they are added to params_filters as partial regex" do
544
-
545
- Bugsnag.configuration.params_filters << /r_data/
546
- Bugsnag.notify(BugsnagTestException.new("It crashed"), {:request => {:params => {:password => "1234", :other_password => "123456", :other_data => "123456"}}})
547
-
548
- expect(Bugsnag).to have_sent_notification{ |payload|
549
- event = get_event_from_payload(payload)
550
- expect(event["metaData"]).not_to be_nil
551
- expect(event["metaData"]["request"]).not_to be_nil
552
- expect(event["metaData"]["request"]["params"]).not_to be_nil
553
- expect(event["metaData"]["request"]["params"]["password"]).to eq("[FILTERED]")
554
- expect(event["metaData"]["request"]["params"]["other_password"]).to eq("[FILTERED]")
555
- expect(event["metaData"]["request"]["params"]["other_data"]).to eq("[FILTERED]")
556
- }
557
- end
558
-
559
- it "does not filter params from payload hashes if their values are nil" do
560
- Bugsnag.notify(BugsnagTestException.new("It crashed"), {:request => {:params => {:nil_param => nil}}})
561
-
562
- expect(Bugsnag).to have_sent_notification{ |payload|
563
- event = get_event_from_payload(payload)
564
- expect(event["metaData"]).not_to be_nil
565
- expect(event["metaData"]["request"]).not_to be_nil
566
- expect(event["metaData"]["request"]["params"]).not_to be_nil
567
- expect(event["metaData"]["request"]["params"]).to have_key("nil_param")
568
- }
569
- end
570
-
571
- it "does not notify if the exception class is in the default ignore_classes list" do
572
- Bugsnag.notify_or_ignore(ActiveRecord::RecordNotFound.new("It crashed"))
573
-
574
- expect(Bugsnag).not_to have_sent_notification
575
- end
576
-
577
- it "does not notify if the non-default exception class is added to the ignore_classes" do
578
- Bugsnag.configuration.ignore_classes << "BugsnagTestException"
579
-
580
- Bugsnag.notify_or_ignore(BugsnagTestException.new("It crashed"))
581
-
582
- expect(Bugsnag).not_to have_sent_notification
583
- end
584
-
585
- it "does not notify if exception's ancestor is an ignored class" do
586
- Bugsnag.configuration.ignore_classes << "BugsnagTestException"
587
-
588
- Bugsnag.notify_or_ignore(BugsnagSubclassTestException.new("It crashed"))
589
-
590
- expect(Bugsnag).not_to have_sent_notification
591
- end
592
-
593
- it "does not notify if any caused exception is an ignored class" do
594
- Bugsnag.configuration.ignore_classes << "NestedException"
595
-
596
- ex = NestedException.new("Self-referential exception")
597
- ex.original_exception = BugsnagTestException.new("It crashed")
598
-
599
- Bugsnag.notify_or_ignore(ex)
600
-
601
- expect(Bugsnag).not_to have_sent_notification
602
- end
603
-
604
- it "accepts both String and Class instances as an ignored class" do
605
- Bugsnag.configuration.ignore_classes << BugsnagTestException
606
-
607
- Bugsnag.notify_or_ignore(BugsnagTestException.new("It crashed"))
608
-
609
- expect(Bugsnag).not_to have_sent_notification
610
- end
611
-
612
- it "does not notify if the user agent is present and matches a regex in ignore_user_agents" do
613
- Bugsnag.configuration.ignore_user_agents << %r{BugsnagUserAgent}
614
-
615
- ((Thread.current["bugsnag_req_data"] ||= {})[:rack_env] ||= {})["HTTP_USER_AGENT"] = "BugsnagUserAgent"
616
-
617
- Bugsnag.notify_or_ignore(BugsnagTestException.new("It crashed"))
618
-
619
- expect(Bugsnag::Notification).not_to have_sent_notification
620
- end
621
-
622
- it "sends the cause of the exception" do
623
- begin
624
- begin
625
- raise "jiminey"
626
- rescue
627
- Ruby21Exception.raise! "cricket"
628
- end
629
- rescue
630
- Bugsnag.notify $!
631
- end
632
-
633
- expect(Bugsnag).to have_sent_notification{ |payload|
634
- event = get_event_from_payload(payload)
635
- expect(event["exceptions"].size).to eq(2)
636
- }
637
- end
638
-
639
- it "does not unwrap the same exception twice" do
640
- ex = NestedException.new("Self-referential exception")
641
- ex.original_exception = ex
642
-
643
- Bugsnag.notify_or_ignore(ex)
644
-
645
- expect(Bugsnag).to have_sent_notification{ |payload|
646
- event = get_event_from_payload(payload)
647
- expect(event["exceptions"].size).to eq(1)
648
- }
649
- end
650
-
651
- it "does not unwrap more than 5 exceptions" do
652
-
653
- first_ex = ex = NestedException.new("Deep exception")
654
- 10.times do |idx|
655
- ex = ex.original_exception = NestedException.new("Deep exception #{idx}")
656
- end
657
-
658
- Bugsnag.notify_or_ignore(first_ex)
659
- expect(Bugsnag).to have_sent_notification{ |payload|
660
- event = get_event_from_payload(payload)
661
- expect(event["exceptions"].size).to eq(5)
662
- }
663
- end
664
-
665
- it "calls to_exception on i18n error objects" do
666
- Bugsnag.notify(OpenStruct.new(:to_exception => BugsnagTestException.new("message")))
667
-
668
- expect(Bugsnag).to have_sent_notification{ |payload|
669
- exception = get_exception_from_payload(payload)
670
- expect(exception["errorClass"]).to eq("BugsnagTestException")
671
- expect(exception["message"]).to eq("message")
672
- }
673
- end
674
-
675
- it "generates runtimeerror for non exceptions" do
676
- notify_test_exception
677
-
678
- expect(Bugsnag).to have_sent_notification{ |payload|
679
- exception = get_exception_from_payload(payload)
680
- expect(exception["errorClass"]).to eq("RuntimeError")
681
- expect(exception["message"]).to eq("test message")
682
- }
683
- end
684
-
685
- it "supports unix-style paths in backtraces" do
686
- ex = BugsnagTestException.new("It crashed")
687
- ex.set_backtrace([
688
- "/Users/james/app/spec/notification_spec.rb:419",
689
- "/Some/path/rspec/example.rb:113:in `instance_eval'"
690
- ])
691
-
692
- Bugsnag.notify(ex)
693
-
694
- expect(Bugsnag).to have_sent_notification{ |payload|
695
- exception = get_exception_from_payload(payload)
696
- expect(exception["stacktrace"].length).to eq(2)
697
-
698
- line = exception["stacktrace"][0]
699
- expect(line["file"]).to eq("/Users/james/app/spec/notification_spec.rb")
700
- expect(line["lineNumber"]).to eq(419)
701
- expect(line["method"]).to be nil
702
-
703
- line = exception["stacktrace"][1]
704
- expect(line["file"]).to eq("/Some/path/rspec/example.rb")
705
- expect(line["lineNumber"]).to eq(113)
706
- expect(line["method"]).to eq("instance_eval")
707
- }
708
- end
709
-
710
- it "supports windows-style paths in backtraces" do
711
- ex = BugsnagTestException.new("It crashed")
712
- ex.set_backtrace([
713
- "C:/projects/test/app/controllers/users_controller.rb:13:in `index'",
714
- "C:/ruby/1.9.1/gems/actionpack-2.3.10/filters.rb:638:in `block in run_before_filters'"
715
- ])
716
-
717
- Bugsnag.notify(ex)
718
-
719
- expect(Bugsnag).to have_sent_notification{ |payload|
720
- exception = get_exception_from_payload(payload)
721
- expect(exception["stacktrace"].length).to eq(2)
722
-
723
- line = exception["stacktrace"][0]
724
- expect(line["file"]).to eq("C:/projects/test/app/controllers/users_controller.rb")
725
- expect(line["lineNumber"]).to eq(13)
726
- expect(line["method"]).to eq("index")
727
-
728
- line = exception["stacktrace"][1]
729
- expect(line["file"]).to eq("C:/ruby/1.9.1/gems/actionpack-2.3.10/filters.rb")
730
- expect(line["lineNumber"]).to eq(638)
731
- expect(line["method"]).to eq("block in run_before_filters")
732
- }
733
- end
734
-
735
- it "should fix invalid utf8" do
736
- invalid_data = "fl\xc3ff"
737
- invalid_data.force_encoding('BINARY') if invalid_data.respond_to?(:force_encoding)
738
-
739
- notify_test_exception(:fluff => {:fluff => invalid_data})
740
-
741
- expect(Bugsnag).to have_sent_notification{ |payload|
742
- if defined?(Encoding::UTF_8)
743
- expect(payload.to_json).to match(/fl�ff/)
744
- else
745
- expect(payload.to_json).to match(/flff/)
746
- end
747
- }
748
- end
749
-
750
- it "should handle utf8 encoding errors in exceptions_list" do
751
- invalid_data = "\"foo\xEBbar\""
752
- invalid_data = invalid_data.force_encoding("utf-8") if invalid_data.respond_to?(:force_encoding)
753
-
754
- begin
755
- JSON.parse(invalid_data)
756
- rescue
757
- Bugsnag.notify $!
758
- end
759
-
760
- expect(Bugsnag).to have_sent_notification { |payload|
761
- if defined?(Encoding::UTF_8)
762
- expect(payload.to_json).to match(/foo�bar/)
763
- else
764
- expect(payload.to_json).to match(/foobar/)
765
- end
766
- }
767
- end
768
-
769
- it "should handle utf8 encoding errors in notification context" do
770
- invalid_data = "\"foo\xEBbar\""
771
- invalid_data = invalid_data.force_encoding("utf-8") if invalid_data.respond_to?(:force_encoding)
772
-
773
- begin
774
- raise
775
- rescue
776
- Bugsnag.notify($!, { :context => invalid_data })
777
- end
778
-
779
- expect(Bugsnag).to have_sent_notification { |payload|
780
- if defined?(Encoding::UTF_8)
781
- expect(payload.to_json).to match(/foo�bar/)
782
- else
783
- expect(payload.to_json).to match(/foobar/)
784
- end
785
- }
786
- end
787
-
788
- it "should handle utf8 encoding errors in notification app fields" do
789
- invalid_data = "\"foo\xEBbar\""
790
- invalid_data = invalid_data.force_encoding("utf-8") if invalid_data.respond_to?(:force_encoding)
791
-
792
- Bugsnag.configuration.app_version = invalid_data
793
- Bugsnag.configuration.release_stage = invalid_data
794
- Bugsnag.configuration.app_type = invalid_data
795
-
796
- begin
797
- raise
798
- rescue
799
- Bugsnag.notify $!
800
- end
801
-
802
- expect(Bugsnag).to have_sent_notification { |payload|
803
- if defined?(Encoding::UTF_8)
804
- expect(payload.to_json).to match(/foo�bar/)
805
- else
806
- expect(payload.to_json).to match(/foobar/)
807
- end
808
- }
809
- end
810
-
811
- it "should handle utf8 encoding errors in grouping_hash" do
812
- invalid_data = "\"foo\xEBbar\""
813
- invalid_data = invalid_data.force_encoding("utf-8") if invalid_data.respond_to?(:force_encoding)
814
-
815
- Bugsnag.before_notify_callbacks << lambda do |notif|
816
- notif.grouping_hash = invalid_data
817
- end
818
-
819
- begin
820
- raise
821
- rescue
822
- Bugsnag.notify $!
823
- end
824
-
825
- expect(Bugsnag).to have_sent_notification { |payload|
826
- if defined?(Encoding::UTF_8)
827
- expect(payload.to_json).to match(/foo�bar/)
828
- else
829
- expect(payload.to_json).to match(/foobar/)
830
- end
831
- }
832
- end
833
-
834
- it "should handle utf8 encoding errors in notification user fields" do
835
- invalid_data = "\"foo\xEBbar\""
836
- invalid_data = invalid_data.force_encoding("utf-8") if invalid_data.respond_to?(:force_encoding)
837
-
838
- Bugsnag.before_notify_callbacks << lambda do |notif|
839
- notif.user = {
840
- :email => "#{invalid_data}@foo.com",
841
- :name => invalid_data
842
- }
843
- end
844
-
845
- begin
846
- raise
847
- rescue
848
- Bugsnag.notify $!
849
- end
850
-
851
- expect(Bugsnag).to have_sent_notification { |payload|
852
- if defined?(Encoding::UTF_8)
853
- expect(payload.to_json).to match(/foo�bar/)
854
- else
855
- expect(payload.to_json).to match(/foobar/)
856
- end
857
- }
858
- end
859
-
860
- if defined?(JRUBY_VERSION)
861
-
862
- it "should work with java.lang.Throwables" do
863
- begin
864
- JRubyException.raise!
865
- rescue
866
- Bugsnag.notify $!
867
- end
868
-
869
- expect(Bugsnag).to have_sent_notification{ |payload|
870
- exception = get_exception_from_payload(payload)
871
- expect(exception["errorClass"]).to eq('Java::JavaLang::ArrayIndexOutOfBoundsException')
872
- expect(exception["message"]).to eq("2")
873
- expect(exception["stacktrace"].size).to be > 0
874
- }
875
- end
876
- end
877
- end