exception_notification 4.4.0 → 4.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/Appraisals +3 -1
  3. data/CHANGELOG.rdoc +10 -0
  4. data/Gemfile +2 -0
  5. data/README.md +34 -8
  6. data/Rakefile +2 -0
  7. data/examples/sample_app.rb +2 -0
  8. data/examples/sinatra/Gemfile +2 -0
  9. data/examples/sinatra/config.ru +2 -0
  10. data/examples/sinatra/sinatra_app.rb +6 -2
  11. data/exception_notification.gemspec +9 -8
  12. data/gemfiles/rails4_0.gemfile +3 -3
  13. data/gemfiles/rails4_1.gemfile +3 -3
  14. data/gemfiles/rails4_2.gemfile +3 -3
  15. data/gemfiles/rails5_0.gemfile +3 -3
  16. data/gemfiles/rails5_1.gemfile +3 -3
  17. data/gemfiles/rails5_2.gemfile +3 -3
  18. data/lib/exception_notification.rb +2 -0
  19. data/lib/exception_notification/rack.rb +24 -13
  20. data/lib/exception_notification/rails.rb +2 -0
  21. data/lib/exception_notification/resque.rb +2 -0
  22. data/lib/exception_notification/sidekiq.rb +5 -3
  23. data/lib/exception_notification/version.rb +3 -1
  24. data/lib/exception_notifier.rb +46 -7
  25. data/lib/exception_notifier/base_notifier.rb +8 -2
  26. data/lib/exception_notifier/campfire_notifier.rb +2 -0
  27. data/lib/exception_notifier/datadog_notifier.rb +12 -9
  28. data/lib/exception_notifier/email_notifier.rb +11 -3
  29. data/lib/exception_notifier/google_chat_notifier.rb +2 -0
  30. data/lib/exception_notifier/hipchat_notifier.rb +2 -0
  31. data/lib/exception_notifier/irc_notifier.rb +4 -3
  32. data/lib/exception_notifier/mattermost_notifier.rb +10 -0
  33. data/lib/exception_notifier/modules/backtrace_cleaner.rb +2 -0
  34. data/lib/exception_notifier/modules/error_grouping.rb +19 -9
  35. data/lib/exception_notifier/modules/formatter.rb +3 -0
  36. data/lib/exception_notifier/notifier.rb +5 -1
  37. data/lib/exception_notifier/slack_notifier.rb +2 -0
  38. data/lib/exception_notifier/sns_notifier.rb +4 -3
  39. data/lib/exception_notifier/teams_notifier.rb +10 -3
  40. data/lib/exception_notifier/webhook_notifier.rb +3 -3
  41. data/lib/generators/exception_notification/install_generator.rb +8 -2
  42. data/test/exception_notification/rack_test.rb +48 -2
  43. data/test/exception_notification/resque_test.rb +2 -0
  44. data/test/exception_notifier/campfire_notifier_test.rb +8 -1
  45. data/test/exception_notifier/datadog_notifier_test.rb +2 -0
  46. data/test/exception_notifier/email_notifier_test.rb +29 -3
  47. data/test/exception_notifier/google_chat_notifier_test.rb +15 -11
  48. data/test/exception_notifier/hipchat_notifier_test.rb +8 -2
  49. data/test/exception_notifier/irc_notifier_test.rb +2 -0
  50. data/test/exception_notifier/mattermost_notifier_test.rb +73 -24
  51. data/test/exception_notifier/modules/error_grouping_test.rb +2 -0
  52. data/test/exception_notifier/modules/formatter_test.rb +2 -0
  53. data/test/exception_notifier/sidekiq_test.rb +3 -11
  54. data/test/exception_notifier/slack_notifier_test.rb +12 -10
  55. data/test/exception_notifier/sns_notifier_test.rb +9 -7
  56. data/test/exception_notifier/teams_notifier_test.rb +2 -0
  57. data/test/exception_notifier/webhook_notifier_test.rb +6 -4
  58. data/test/exception_notifier_test.rb +112 -6
  59. data/test/support/exception_notifier_helper.rb +14 -0
  60. data/test/test_helper.rb +5 -1
  61. metadata +22 -27
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  require 'exception_notification/resque'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  # silence_warnings trick around require can be removed once
@@ -94,11 +96,16 @@ class CampfireNotifierTest < ActiveSupport::TestCase
94
96
  {
95
97
  message: {
96
98
  type: 'PasteMessage',
97
- body: "A new exception occurred: 'divided by 0' on '/Users/sebastian/exception_notification/test/campfire_test.rb:45:in `/'"
99
+ body: fake_notification_body
98
100
  }
99
101
  }
100
102
  end
101
103
 
104
+ def fake_notification_body
105
+ "A new exception occurred: 'divided by 0' on " \
106
+ "/Users/sebastian/exception_notification/test/campfire_test.rb:45:in `/'"
107
+ end
108
+
102
109
  def fake_exception
103
110
  5 / 0
104
111
  rescue StandardError => e
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'dogapi/common'
3
5
  require 'dogapi/event'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'action_mailer'
3
5
  require 'action_controller'
@@ -116,7 +118,7 @@ class EmailNotifierTest < ActiveSupport::TestCase
116
118
  env: {
117
119
  'REQUEST_METHOD' => 'GET',
118
120
  'rack.input' => '',
119
- 'invalid_encoding' => "R\xC3\xA9sum\xC3\xA9".force_encoding(Encoding::ASCII)
121
+ 'invalid_encoding' => "R\xC3\xA9sum\xC3\xA9".dup.force_encoding(Encoding::ASCII)
120
122
  }
121
123
  )
122
124
 
@@ -220,8 +222,10 @@ class EmailNotifierWithEnvTest < ActiveSupport::TestCase
220
222
  email_headers: { 'X-Custom-Header' => 'foobar' },
221
223
  sections: %w[new_section request session environment backtrace],
222
224
  background_sections: %w[new_bkg_section backtrace data],
223
- pre_callback: proc { |_opts, _notifier, _backtrace, _message, message_opts| message_opts[:pre_callback_called] = 1 },
224
- post_callback: proc { |_opts, _notifier, _backtrace, _message, message_opts| message_opts[:post_callback_called] = 1 }
225
+ pre_callback:
226
+ proc { |_opts, _notifier, _backtrace, _message, message_opts| message_opts[:pre_callback_called] = 1 },
227
+ post_callback:
228
+ proc { |_opts, _notifier, _backtrace, _message, message_opts| message_opts[:post_callback_called] = 1 }
225
229
  )
226
230
 
227
231
  @controller = HomeController.new
@@ -349,3 +353,25 @@ class EmailNotifierWithEnvTest < ActiveSupport::TestCase
349
353
  assert_equal '[ERROR] (ZeroDivisionError) "divided by 0"', mail.subject
350
354
  end
351
355
  end
356
+
357
+ class EmailNotifierWithCustomParentClassTest < ActiveSupport::TestCase
358
+ class ApplicationMailer < ActionMailer::Base
359
+ default from: 'infrastructure@example.com'
360
+ end
361
+
362
+ setup do
363
+ @exception = ZeroDivisionError.new('divided by 0')
364
+ @exception.set_backtrace(["#{__FILE__}:#{__LINE__}"])
365
+ end
366
+
367
+ test 'uses default from configured parent class' do
368
+ email_notifier = ExceptionNotifier::EmailNotifier.new(
369
+ mailer_parent: 'EmailNotifierWithCustomParentClassTest::ApplicationMailer',
370
+ exception_recipients: %w[dummyexceptions@example.com]
371
+ )
372
+ mail = email_notifier.call(@exception)
373
+
374
+ assert email_notifier.__send__(:mailer) < ApplicationMailer
375
+ assert_equal ['infrastructure@example.com'], mail.from
376
+ end
377
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'rack'
3
5
  require 'httparty'
@@ -5,7 +7,7 @@ require 'timecop'
5
7
  require 'json'
6
8
 
7
9
  class GoogleChatNotifierTest < ActiveSupport::TestCase
8
- URL = 'http://localhost:8000'.freeze
10
+ URL = 'http://localhost:8000'
9
11
 
10
12
  def setup
11
13
  Timecop.freeze('2018-12-09 12:07:16 UTC')
@@ -59,11 +61,7 @@ class GoogleChatNotifierTest < ActiveSupport::TestCase
59
61
  header,
60
62
  body,
61
63
  '',
62
- '*Backtrace:*',
63
- '```',
64
- "* app/controllers/my_controller.rb:53:in `my_controller_params'",
65
- "* app/controllers/my_controller.rb:34:in `update'",
66
- '```'
64
+ backtrace
67
65
  ].join("\n")
68
66
 
69
67
  HTTParty.expects(:post).with(URL, post_opts(text))
@@ -117,11 +115,7 @@ class GoogleChatNotifierTest < ActiveSupport::TestCase
117
115
  '* timestamp : 2018-12-09 12:07:16 UTC',
118
116
  '```',
119
117
  '',
120
- '*Backtrace:*',
121
- '```',
122
- "* app/controllers/my_controller.rb:53:in `my_controller_params'",
123
- "* app/controllers/my_controller.rb:34:in `update'",
124
- '```'
118
+ backtrace
125
119
  ].join("\n")
126
120
 
127
121
  HTTParty.expects(:post).with(URL, post_opts(text))
@@ -178,4 +172,14 @@ class GoogleChatNotifierTest < ActiveSupport::TestCase
178
172
  def app_name
179
173
  'dummy' if defined?(::Rails) && ::Rails.respond_to?(:application)
180
174
  end
175
+
176
+ def backtrace
177
+ [
178
+ '*Backtrace:*',
179
+ '```',
180
+ "* app/controllers/my_controller.rb:53:in `my_controller_params'",
181
+ "* app/controllers/my_controller.rb:34:in `update'",
182
+ '```'
183
+ ]
184
+ end
181
185
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'rack'
3
5
 
@@ -33,7 +35,9 @@ class HipchatNotifierTest < ActiveSupport::TestCase
33
35
  post_callback: proc { |*| post_callback_called += 1 }
34
36
  }
35
37
 
36
- HipChat::Room.any_instance.expects(:send).with('Exception', fake_body, { color: 'yellow' }.merge(options.except(:api_token, :room_name)))
38
+ HipChat::Room.any_instance
39
+ .expects(:send)
40
+ .with('Exception', fake_body, { color: 'yellow' }.merge(options.except(:api_token, :room_name)))
37
41
 
38
42
  hipchat = ExceptionNotifier::HipchatNotifier.new(options)
39
43
  hipchat.call(fake_exception)
@@ -105,7 +109,9 @@ class HipchatNotifierTest < ActiveSupport::TestCase
105
109
  message_template: ->(exception, _) { "This is custom message: '#{exception.message}'" }
106
110
  }
107
111
 
108
- HipChat::Room.any_instance.expects(:send).with('Exception', "This is custom message: '#{fake_exception.message}'", color: 'yellow')
112
+ HipChat::Room.any_instance
113
+ .expects(:send)
114
+ .with('Exception', "This is custom message: '#{fake_exception.message}'", color: 'yellow')
109
115
 
110
116
  hipchat = ExceptionNotifier::HipchatNotifier.new(options)
111
117
  hipchat.call(fake_exception)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'carrier-pigeon'
3
5
 
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'httparty'
3
5
  require 'timecop'
4
6
  require 'json'
5
7
 
6
8
  class MattermostNotifierTest < ActiveSupport::TestCase
7
- URL = 'http://localhost:8000'.freeze
9
+ URL = 'http://localhost:8000'
8
10
 
9
11
  def setup
10
12
  Timecop.freeze('2018-12-09 12:07:16 UTC')
@@ -113,27 +115,14 @@ class MattermostNotifierTest < ActiveSupport::TestCase
113
115
  end
114
116
 
115
117
  test 'should include backtrace and request info' do
116
- body = default_body.merge(
117
- text: [
118
- '@channel',
119
- error_occurred_in,
120
- 'An *ArgumentError* occurred.',
121
- '*foo*',
122
- '### Request',
123
- '```',
124
- '* url : http://test.address/?id=foo',
125
- '* http_method : GET',
126
- '* ip_address : 127.0.0.1',
127
- '* parameters : {"id"=>"foo"}',
128
- '* timestamp : 2018-12-09 12:07:16 UTC',
129
- '```',
130
- '### Backtrace',
131
- '```',
132
- "* app/controllers/my_controller.rb:53:in `my_controller_params'",
133
- "* app/controllers/my_controller.rb:34:in `update'",
134
- '```'
135
- ].join("\n")
136
- )
118
+ body = default_body.merge(text: [
119
+ '@channel',
120
+ error_occurred_in,
121
+ 'An *ArgumentError* occurred.',
122
+ '*foo*',
123
+ request_info,
124
+ backtrace_info
125
+ ].join("\n"))
137
126
 
138
127
  opts = {
139
128
  body: body.to_json,
@@ -151,6 +140,31 @@ class MattermostNotifierTest < ActiveSupport::TestCase
151
140
  notifier.call(exception, env: test_env)
152
141
  end
153
142
 
143
+ test 'should include exception_data_info' do
144
+ body = default_body.merge(
145
+ text: [
146
+ '@channel',
147
+ error_occurred_in,
148
+ 'An *ArgumentError* occurred.',
149
+ '*foo*',
150
+ request_info,
151
+ exception_data_info
152
+ ].join("\n")
153
+ )
154
+
155
+ opts = {
156
+ body: body.to_json,
157
+ headers: default_headers
158
+ }
159
+
160
+ env = test_env.merge(
161
+ 'exception_notifier.exception_data' => { foo: 'bar', john: 'doe' }
162
+ )
163
+
164
+ HTTParty.expects(:post).with(URL, opts)
165
+ notifier.call(ArgumentError.new('foo'), env: env)
166
+ end
167
+
154
168
  private
155
169
 
156
170
  def notifier
@@ -193,10 +207,45 @@ class MattermostNotifierTest < ActiveSupport::TestCase
193
207
 
194
208
  def github_link
195
209
  if defined?(::Rails) && ::Rails.respond_to?(:application)
196
- '[Create an issue](github.com/aschen/dummy/issues/new/?issue%5Btitle%5D=%5BBUG%5D+Error+500+%3A++%28ArgumentError%29+foo)'
210
+ '[Create an issue]' \
211
+ '(github.com/aschen/dummy/issues/new/?issue%5Btitle%5D=%5BBUG%5D+Error+500+%3A++%28ArgumentError%29+foo)'
197
212
  else
198
213
  # TODO: fix missing app name
199
- '[Create an issue](github.com/aschen//issues/new/?issue%5Btitle%5D=%5BBUG%5D+Error+500+%3A++%28ArgumentError%29+foo)'
214
+ '[Create an issue]' \
215
+ '(github.com/aschen//issues/new/?issue%5Btitle%5D=%5BBUG%5D+Error+500+%3A++%28ArgumentError%29+foo)'
200
216
  end
201
217
  end
218
+
219
+ def request_info
220
+ [
221
+ '### Request',
222
+ '```',
223
+ '* url : http://test.address/?id=foo',
224
+ '* http_method : GET',
225
+ '* ip_address : 127.0.0.1',
226
+ '* parameters : {"id"=>"foo"}',
227
+ '* timestamp : 2018-12-09 12:07:16 UTC',
228
+ '```'
229
+ ]
230
+ end
231
+
232
+ def backtrace_info
233
+ [
234
+ '### Backtrace',
235
+ '```',
236
+ "* app/controllers/my_controller.rb:53:in `my_controller_params'",
237
+ "* app/controllers/my_controller.rb:34:in `update'",
238
+ '```'
239
+ ]
240
+ end
241
+
242
+ def exception_data_info
243
+ [
244
+ '### Data',
245
+ '```',
246
+ '* foo : bar',
247
+ '* john : doe',
248
+ '```'
249
+ ]
250
+ end
202
251
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  class ErrorGroupTest < ActiveSupport::TestCase
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'timecop'
3
5
 
@@ -1,9 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
5
  # To allow sidekiq error handlers to be registered, sidekiq must be in
4
6
  # "server mode". This mode is triggered by loading sidekiq/cli. Note this
5
7
  # has to be loaded before exception_notification/sidekiq.
6
8
  require 'sidekiq/cli'
9
+ require 'sidekiq/testing'
7
10
 
8
11
  require 'exception_notification/sidekiq'
9
12
 
@@ -12,13 +15,6 @@ class MockSidekiqServer
12
15
  end
13
16
 
14
17
  class SidekiqTest < ActiveSupport::TestCase
15
- setup do
16
- @_original_sidekiq_logger = Sidekiq::Logging.logger
17
-
18
- # Silence sidekiq warning to stdout
19
- Sidekiq::Logging.logger = nil
20
- end
21
-
22
18
  test 'should call notify_exception when sidekiq raises an error' do
23
19
  server = MockSidekiqServer.new
24
20
  message = {}
@@ -31,8 +27,4 @@ class SidekiqTest < ActiveSupport::TestCase
31
27
 
32
28
  server.handle_exception(exception, message)
33
29
  end
34
-
35
- teardown do
36
- Sidekiq::Logging.logger = @_original_sidekiq_logger
37
- end
38
30
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'slack-notifier'
3
5
 
@@ -128,15 +130,17 @@ class SlackNotifierTest < ActiveSupport::TestCase
128
130
  'exception_notifier.exception_data' => { foo: 'bar', john: 'doe' }
129
131
  },
130
132
  data: {
131
- 'user_id' => 5,
133
+ 'user_id' => 5,
132
134
  'key_to_be_ignored' => 'whatever',
133
- 'ignore_as_well' => { what: 'ever' }
135
+ 'ignore_as_well' => { what: 'ever' }
134
136
  }
135
137
  }
136
138
 
137
139
  expected_data_string = "foo: bar\njohn: doe\nuser_id: 5"
138
140
 
139
- Slack::Notifier.any_instance.expects(:ping).with('', fake_notification(@exception, notification_options, expected_data_string))
141
+ Slack::Notifier.any_instance
142
+ .expects(:ping)
143
+ .with('', fake_notification(@exception, notification_options, expected_data_string))
140
144
  slack_notifier = ExceptionNotifier::SlackNotifier.new(options)
141
145
  slack_notifier.call(@exception, notification_options)
142
146
  end
@@ -184,12 +188,8 @@ class SlackNotifierTest < ActiveSupport::TestCase
184
188
 
185
189
  def fake_backtrace
186
190
  [
187
- 'backtrace line 1',
188
- 'backtrace line 2',
189
- 'backtrace line 3',
190
- 'backtrace line 4',
191
- 'backtrace line 5',
192
- 'backtrace line 6'
191
+ 'backtrace line 1', 'backtrace line 2', 'backtrace line 3',
192
+ 'backtrace line 4', 'backtrace line 5', 'backtrace line 6'
193
193
  ]
194
194
  end
195
195
 
@@ -197,7 +197,9 @@ class SlackNotifierTest < ActiveSupport::TestCase
197
197
  fake_backtrace[2..-1]
198
198
  end
199
199
 
200
- def fake_notification(exception = @exception, notification_options = {}, data_string = nil, expected_backtrace_lines = 10, additional_fields = [])
200
+ def fake_notification(exception = @exception, notification_options = {},
201
+ data_string = nil, expected_backtrace_lines = 10, additional_fields = [])
202
+
201
203
  exception_name = "*#{exception.class.to_s =~ /^[aeiou]/i ? 'An' : 'A'}* `#{exception.class}`"
202
204
  if notification_options[:env].nil?
203
205
  text = "#{exception_name} *occured in background*"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'aws-sdk-sns'
3
5
 
@@ -61,9 +63,9 @@ class SnsNotifierTest < ActiveSupport::TestCase
61
63
  test 'should send a sns notification in background' do
62
64
  Aws::SNS::Client.any_instance.expects(:publish).with(
63
65
  topic_arn: 'topicARN',
64
- message: "3 MyException occured in background\n"\
65
- "Exception: undefined method 'method=' for Empty\n"\
66
- "Hostname: example.com\n"\
66
+ message: "3 MyException occured in background\n" \
67
+ "Exception: undefined method 'method=' for Empty\n" \
68
+ "Hostname: example.com\n" \
67
69
  "Backtrace:\n#{fake_backtrace.join("\n")}\n",
68
70
  subject: '[App Exception] - 3 MyException occurred'
69
71
  )
@@ -79,10 +81,10 @@ class SnsNotifierTest < ActiveSupport::TestCase
79
81
 
80
82
  Aws::SNS::Client.any_instance.expects(:publish).with(
81
83
  topic_arn: 'topicARN',
82
- message: 'A MyException occurred while GET </examples> '\
83
- "was processed by examples#index\n"\
84
- "Exception: undefined method 'method=' for Empty\n"\
85
- "Hostname: example.com\n"\
84
+ message: 'A MyException occurred while GET </examples> ' \
85
+ "was processed by examples#index\n" \
86
+ "Exception: undefined method 'method=' for Empty\n" \
87
+ "Hostname: example.com\n" \
86
88
  "Backtrace:\n#{fake_backtrace.join("\n")}\n",
87
89
  subject: '[App Exception] - A MyException occurred'
88
90
  )
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
  require 'httparty'
3
5