exception_notification 3.0.1 → 4.4.0

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 (153) hide show
  1. checksums.yaml +7 -0
  2. data/Appraisals +7 -0
  3. data/CHANGELOG.rdoc +129 -1
  4. data/CODE_OF_CONDUCT.md +22 -0
  5. data/CONTRIBUTING.md +29 -1
  6. data/Gemfile +1 -1
  7. data/MIT-LICENSE +23 -0
  8. data/README.md +168 -222
  9. data/Rakefile +5 -11
  10. data/docs/notifiers/campfire.md +50 -0
  11. data/docs/notifiers/custom.md +42 -0
  12. data/docs/notifiers/datadog.md +51 -0
  13. data/docs/notifiers/email.md +195 -0
  14. data/docs/notifiers/google_chat.md +31 -0
  15. data/docs/notifiers/hipchat.md +66 -0
  16. data/docs/notifiers/irc.md +97 -0
  17. data/docs/notifiers/mattermost.md +115 -0
  18. data/docs/notifiers/slack.md +161 -0
  19. data/docs/notifiers/sns.md +37 -0
  20. data/docs/notifiers/teams.md +54 -0
  21. data/docs/notifiers/webhook.md +60 -0
  22. data/examples/sample_app.rb +54 -0
  23. data/examples/sinatra/Gemfile +8 -0
  24. data/examples/sinatra/Gemfile.lock +95 -0
  25. data/examples/sinatra/Procfile +2 -0
  26. data/examples/sinatra/README.md +11 -0
  27. data/examples/sinatra/config.ru +3 -0
  28. data/examples/sinatra/sinatra_app.rb +36 -0
  29. data/exception_notification.gemspec +32 -11
  30. data/gemfiles/rails4_0.gemfile +7 -0
  31. data/gemfiles/rails4_1.gemfile +7 -0
  32. data/gemfiles/rails4_2.gemfile +7 -0
  33. data/gemfiles/rails5_0.gemfile +7 -0
  34. data/gemfiles/rails5_1.gemfile +7 -0
  35. data/gemfiles/rails5_2.gemfile +7 -0
  36. data/gemfiles/rails6_0.gemfile +7 -0
  37. data/lib/exception_notification.rb +11 -0
  38. data/lib/exception_notification/rack.rb +55 -0
  39. data/lib/exception_notification/rails.rb +9 -0
  40. data/lib/exception_notification/resque.rb +22 -0
  41. data/lib/exception_notification/sidekiq.rb +27 -0
  42. data/lib/exception_notification/version.rb +3 -0
  43. data/lib/exception_notifier.rb +137 -61
  44. data/lib/exception_notifier/base_notifier.rb +24 -0
  45. data/lib/exception_notifier/campfire_notifier.rb +16 -11
  46. data/lib/exception_notifier/datadog_notifier.rb +153 -0
  47. data/lib/exception_notifier/email_notifier.rb +196 -0
  48. data/lib/exception_notifier/google_chat_notifier.rb +42 -0
  49. data/lib/exception_notifier/hipchat_notifier.rb +49 -0
  50. data/lib/exception_notifier/irc_notifier.rb +57 -0
  51. data/lib/exception_notifier/mattermost_notifier.rb +72 -0
  52. data/lib/exception_notifier/modules/backtrace_cleaner.rb +11 -0
  53. data/lib/exception_notifier/modules/error_grouping.rb +77 -0
  54. data/lib/exception_notifier/modules/formatter.rb +118 -0
  55. data/lib/exception_notifier/notifier.rb +9 -179
  56. data/lib/exception_notifier/slack_notifier.rb +111 -0
  57. data/lib/exception_notifier/sns_notifier.rb +85 -0
  58. data/lib/exception_notifier/teams_notifier.rb +193 -0
  59. data/lib/exception_notifier/views/exception_notifier/_backtrace.html.erb +3 -1
  60. data/lib/exception_notifier/views/exception_notifier/_data.html.erb +6 -1
  61. data/lib/exception_notifier/views/exception_notifier/_environment.html.erb +8 -6
  62. data/lib/exception_notifier/views/exception_notifier/_environment.text.erb +1 -4
  63. data/lib/exception_notifier/views/exception_notifier/_request.html.erb +36 -5
  64. data/lib/exception_notifier/views/exception_notifier/_request.text.erb +10 -5
  65. data/lib/exception_notifier/views/exception_notifier/_session.html.erb +10 -2
  66. data/lib/exception_notifier/views/exception_notifier/_session.text.erb +2 -2
  67. data/lib/exception_notifier/views/exception_notifier/_title.html.erb +3 -3
  68. data/lib/exception_notifier/views/exception_notifier/background_exception_notification.html.erb +38 -11
  69. data/lib/exception_notifier/views/exception_notifier/background_exception_notification.text.erb +10 -11
  70. data/lib/exception_notifier/views/exception_notifier/exception_notification.html.erb +38 -22
  71. data/lib/exception_notifier/views/exception_notifier/exception_notification.text.erb +2 -3
  72. data/lib/exception_notifier/webhook_notifier.rb +51 -0
  73. data/lib/generators/exception_notification/install_generator.rb +15 -0
  74. data/lib/generators/exception_notification/templates/exception_notification.rb.erb +55 -0
  75. data/test/exception_notification/rack_test.rb +60 -0
  76. data/test/exception_notification/resque_test.rb +52 -0
  77. data/test/exception_notifier/campfire_notifier_test.rb +120 -0
  78. data/test/exception_notifier/datadog_notifier_test.rb +151 -0
  79. data/test/exception_notifier/email_notifier_test.rb +351 -0
  80. data/test/exception_notifier/google_chat_notifier_test.rb +181 -0
  81. data/test/exception_notifier/hipchat_notifier_test.rb +218 -0
  82. data/test/exception_notifier/irc_notifier_test.rb +137 -0
  83. data/test/exception_notifier/mattermost_notifier_test.rb +202 -0
  84. data/test/exception_notifier/modules/error_grouping_test.rb +165 -0
  85. data/test/exception_notifier/modules/formatter_test.rb +150 -0
  86. data/test/exception_notifier/sidekiq_test.rb +38 -0
  87. data/test/exception_notifier/slack_notifier_test.rb +227 -0
  88. data/test/exception_notifier/sns_notifier_test.rb +121 -0
  89. data/test/exception_notifier/teams_notifier_test.rb +90 -0
  90. data/test/exception_notifier/webhook_notifier_test.rb +96 -0
  91. data/test/exception_notifier_test.rb +182 -0
  92. data/test/{dummy/app → support}/views/exception_notifier/_new_bkg_section.html.erb +0 -0
  93. data/test/{dummy/app → support}/views/exception_notifier/_new_bkg_section.text.erb +0 -0
  94. data/test/{dummy/app → support}/views/exception_notifier/_new_section.html.erb +0 -0
  95. data/test/{dummy/app → support}/views/exception_notifier/_new_section.text.erb +0 -0
  96. data/test/test_helper.rb +12 -8
  97. metadata +333 -164
  98. data/.gemtest +0 -0
  99. data/Gemfile.lock +0 -122
  100. data/test/background_exception_notification_test.rb +0 -82
  101. data/test/campfire_test.rb +0 -53
  102. data/test/dummy/.gitignore +0 -4
  103. data/test/dummy/Gemfile +0 -33
  104. data/test/dummy/Gemfile.lock +0 -118
  105. data/test/dummy/Rakefile +0 -7
  106. data/test/dummy/app/controllers/application_controller.rb +0 -3
  107. data/test/dummy/app/controllers/posts_controller.rb +0 -30
  108. data/test/dummy/app/helpers/application_helper.rb +0 -2
  109. data/test/dummy/app/helpers/posts_helper.rb +0 -2
  110. data/test/dummy/app/models/post.rb +0 -2
  111. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  112. data/test/dummy/app/views/posts/_form.html.erb +0 -0
  113. data/test/dummy/app/views/posts/new.html.erb +0 -0
  114. data/test/dummy/app/views/posts/show.html.erb +0 -0
  115. data/test/dummy/config.ru +0 -4
  116. data/test/dummy/config/application.rb +0 -42
  117. data/test/dummy/config/boot.rb +0 -6
  118. data/test/dummy/config/database.yml +0 -22
  119. data/test/dummy/config/environment.rb +0 -13
  120. data/test/dummy/config/environments/development.rb +0 -24
  121. data/test/dummy/config/environments/production.rb +0 -49
  122. data/test/dummy/config/environments/test.rb +0 -35
  123. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  124. data/test/dummy/config/initializers/inflections.rb +0 -10
  125. data/test/dummy/config/initializers/mime_types.rb +0 -5
  126. data/test/dummy/config/initializers/secret_token.rb +0 -7
  127. data/test/dummy/config/initializers/session_store.rb +0 -8
  128. data/test/dummy/config/locales/en.yml +0 -5
  129. data/test/dummy/config/routes.rb +0 -3
  130. data/test/dummy/db/migrate/20110729022608_create_posts.rb +0 -15
  131. data/test/dummy/db/schema.rb +0 -24
  132. data/test/dummy/db/seeds.rb +0 -7
  133. data/test/dummy/lib/tasks/.gitkeep +0 -0
  134. data/test/dummy/public/404.html +0 -26
  135. data/test/dummy/public/422.html +0 -26
  136. data/test/dummy/public/500.html +0 -26
  137. data/test/dummy/public/favicon.ico +0 -0
  138. data/test/dummy/public/images/rails.png +0 -0
  139. data/test/dummy/public/index.html +0 -239
  140. data/test/dummy/public/javascripts/application.js +0 -2
  141. data/test/dummy/public/javascripts/controls.js +0 -965
  142. data/test/dummy/public/javascripts/dragdrop.js +0 -974
  143. data/test/dummy/public/javascripts/effects.js +0 -1123
  144. data/test/dummy/public/javascripts/prototype.js +0 -6001
  145. data/test/dummy/public/javascripts/rails.js +0 -191
  146. data/test/dummy/public/robots.txt +0 -5
  147. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  148. data/test/dummy/public/stylesheets/scaffold.css +0 -56
  149. data/test/dummy/script/rails +0 -6
  150. data/test/dummy/test/fixtures/posts.yml +0 -11
  151. data/test/dummy/test/functional/posts_controller_test.rb +0 -239
  152. data/test/dummy/test/test_helper.rb +0 -13
  153. data/test/exception_notification_test.rb +0 -73
@@ -0,0 +1,351 @@
1
+ require 'test_helper'
2
+ require 'action_mailer'
3
+ require 'action_controller'
4
+
5
+ class EmailNotifierTest < ActiveSupport::TestCase
6
+ setup do
7
+ Time.stubs(:current).returns('Sat, 20 Apr 2013 20:58:55 UTC +00:00')
8
+
9
+ @exception = ZeroDivisionError.new('divided by 0')
10
+ @exception.set_backtrace(['test/exception_notifier/email_notifier_test.rb:20'])
11
+
12
+ @email_notifier = ExceptionNotifier::EmailNotifier.new(
13
+ email_prefix: '[Dummy ERROR] ',
14
+ sender_address: %("Dummy Notifier" <dummynotifier@example.com>),
15
+ exception_recipients: %w[dummyexceptions@example.com],
16
+ email_headers: { 'X-Custom-Header' => 'foobar' },
17
+ sections: %w[new_section request session environment backtrace],
18
+ background_sections: %w[new_bkg_section backtrace data],
19
+ pre_callback: proc { |_opts, _notifier, _backtrace, _message, _message_opts| @pre_callback_called = true },
20
+ post_callback: proc { |_opts, _notifier, _backtrace, _message, _message_opts| @post_callback_called = true },
21
+ smtp_settings: {
22
+ user_name: 'Dummy user_name',
23
+ password: 'Dummy password'
24
+ }
25
+ )
26
+
27
+ @mail = @email_notifier.call(
28
+ @exception,
29
+ data: { job: 'DivideWorkerJob', payload: '1/0', message: 'My Custom Message' }
30
+ )
31
+ end
32
+
33
+ test 'should call pre/post_callback if specified' do
34
+ assert @pre_callback_called
35
+ assert @post_callback_called
36
+ end
37
+
38
+ test 'sends mail with correct content' do
39
+ assert_equal %("Dummy Notifier" <dummynotifier@example.com>), @mail[:from].value
40
+ assert_equal %w[dummyexceptions@example.com], @mail.to
41
+ assert_equal '[Dummy ERROR] (ZeroDivisionError) "divided by 0"', @mail.subject
42
+ assert_equal 'foobar', @mail['X-Custom-Header'].value
43
+ assert_equal 'text/plain; charset=UTF-8', @mail.content_type
44
+ assert_equal [], @mail.attachments
45
+ assert_equal 'Dummy user_name', @mail.delivery_method.settings[:user_name]
46
+ assert_equal 'Dummy password', @mail.delivery_method.settings[:password]
47
+
48
+ body = <<-BODY.gsub(/^ /, '')
49
+ A ZeroDivisionError occurred in background at Sat, 20 Apr 2013 20:58:55 UTC +00:00 :
50
+
51
+ divided by 0
52
+ test/exception_notifier/email_notifier_test.rb:20
53
+
54
+ -------------------------------
55
+ New bkg section:
56
+ -------------------------------
57
+
58
+ * New background section for testing
59
+
60
+ -------------------------------
61
+ Backtrace:
62
+ -------------------------------
63
+
64
+ test/exception_notifier/email_notifier_test.rb:20
65
+
66
+ -------------------------------
67
+ Data:
68
+ -------------------------------
69
+
70
+ * data: {:job=>"DivideWorkerJob", :payload=>"1/0", :message=>"My Custom Message"}
71
+
72
+
73
+ BODY
74
+
75
+ assert_equal body, @mail.decode_body
76
+ end
77
+
78
+ test 'should normalize multiple digits into one N' do
79
+ assert_equal 'N foo N bar N baz N',
80
+ ExceptionNotifier::EmailNotifier.normalize_digits('1 foo 12 bar 123 baz 1234')
81
+ end
82
+
83
+ test "mail should prefix exception class with 'an' instead of 'a' when it starts with a vowel" do
84
+ begin
85
+ raise ArgumentError
86
+ rescue StandardError => e
87
+ @vowel_exception = e
88
+ @vowel_mail = @email_notifier.call(@vowel_exception)
89
+ end
90
+
91
+ assert_includes @vowel_mail.encoded, "An ArgumentError occurred in background at #{Time.current}"
92
+ end
93
+
94
+ test 'should not send notification if one of ignored exceptions' do
95
+ begin
96
+ raise AbstractController::ActionNotFound
97
+ rescue StandardError => e
98
+ @ignored_exception = e
99
+ unless ExceptionNotifier.ignored_exceptions.include?(@ignored_exception.class.name)
100
+ ignored_mail = @email_notifier.call(@ignored_exception)
101
+ end
102
+ end
103
+
104
+ assert_equal @ignored_exception.class.inspect, 'AbstractController::ActionNotFound'
105
+ assert_nil ignored_mail
106
+ end
107
+
108
+ test 'should encode environment strings' do
109
+ email_notifier = ExceptionNotifier::EmailNotifier.new(
110
+ sender_address: '<dummynotifier@example.com>',
111
+ exception_recipients: %w[dummyexceptions@example.com]
112
+ )
113
+
114
+ mail = email_notifier.call(
115
+ @exception,
116
+ env: {
117
+ 'REQUEST_METHOD' => 'GET',
118
+ 'rack.input' => '',
119
+ 'invalid_encoding' => "R\xC3\xA9sum\xC3\xA9".force_encoding(Encoding::ASCII)
120
+ }
121
+ )
122
+
123
+ assert_match(/invalid_encoding\s+: R__sum__/, mail.encoded)
124
+ end
125
+
126
+ test 'should send email using ActionMailer' do
127
+ ActionMailer::Base.deliveries.clear
128
+ @email_notifier.call(@exception)
129
+ assert_equal 1, ActionMailer::Base.deliveries.count
130
+ end
131
+
132
+ test 'should be able to specify ActionMailer::MessageDelivery method' do
133
+ ActionMailer::Base.deliveries.clear
134
+
135
+ deliver_with = if ActionMailer.version < Gem::Version.new('4.2')
136
+ :deliver
137
+ else
138
+ :deliver_now
139
+ end
140
+
141
+ email_notifier = ExceptionNotifier::EmailNotifier.new(
142
+ email_prefix: '[Dummy ERROR] ',
143
+ sender_address: %("Dummy Notifier" <dummynotifier@example.com>),
144
+ exception_recipients: %w[dummyexceptions@example.com],
145
+ deliver_with: deliver_with
146
+ )
147
+
148
+ email_notifier.call(@exception)
149
+
150
+ assert_equal 1, ActionMailer::Base.deliveries.count
151
+ end
152
+
153
+ test 'should lazily evaluate exception_recipients' do
154
+ exception_recipients = %w[first@example.com second@example.com]
155
+ email_notifier = ExceptionNotifier::EmailNotifier.new(
156
+ email_prefix: '[Dummy ERROR] ',
157
+ sender_address: %("Dummy Notifier" <dummynotifier@example.com>),
158
+ exception_recipients: -> { [exception_recipients.shift] },
159
+ delivery_method: :test
160
+ )
161
+
162
+ mail = email_notifier.call(@exception)
163
+ assert_equal %w[first@example.com], mail.to
164
+ mail = email_notifier.call(@exception)
165
+ assert_equal %w[second@example.com], mail.to
166
+ end
167
+
168
+ test 'should prepend accumulated_errors_count in email subject if accumulated_errors_count larger than 1' do
169
+ email_notifier = ExceptionNotifier::EmailNotifier.new(
170
+ email_prefix: '[Dummy ERROR] ',
171
+ sender_address: %("Dummy Notifier" <dummynotifier@example.com>),
172
+ exception_recipients: %w[dummyexceptions@example.com],
173
+ delivery_method: :test
174
+ )
175
+
176
+ mail = email_notifier.call(@exception, accumulated_errors_count: 3)
177
+ assert mail.subject.start_with?('[Dummy ERROR] (3 times) (ZeroDivisionError)')
178
+ end
179
+
180
+ test 'should not include exception message in subject when verbose_subject: false' do
181
+ email_notifier = ExceptionNotifier::EmailNotifier.new(
182
+ sender_address: %("Dummy Notifier" <dummynotifier@example.com>),
183
+ exception_recipients: %w[dummyexceptions@example.com],
184
+ verbose_subject: false
185
+ )
186
+
187
+ mail = email_notifier.call(@exception)
188
+
189
+ assert_equal '[ERROR] (ZeroDivisionError)', mail.subject
190
+ end
191
+
192
+ test 'should send html email when selected html format' do
193
+ email_notifier = ExceptionNotifier::EmailNotifier.new(
194
+ sender_address: %("Dummy Notifier" <dummynotifier@example.com>),
195
+ exception_recipients: %w[dummyexceptions@example.com],
196
+ email_format: :html
197
+ )
198
+
199
+ mail = email_notifier.call(@exception)
200
+
201
+ assert mail.multipart?
202
+ end
203
+ end
204
+
205
+ class EmailNotifierWithEnvTest < ActiveSupport::TestCase
206
+ class HomeController < ActionController::Metal
207
+ def index; end
208
+ end
209
+
210
+ setup do
211
+ Time.stubs(:current).returns('Sat, 20 Apr 2013 20:58:55 UTC +00:00')
212
+
213
+ @exception = ZeroDivisionError.new('divided by 0')
214
+ @exception.set_backtrace(['test/exception_notifier/email_notifier_test.rb:20'])
215
+
216
+ @email_notifier = ExceptionNotifier::EmailNotifier.new(
217
+ email_prefix: '[Dummy ERROR] ',
218
+ sender_address: %("Dummy Notifier" <dummynotifier@example.com>),
219
+ exception_recipients: %w[dummyexceptions@example.com],
220
+ email_headers: { 'X-Custom-Header' => 'foobar' },
221
+ sections: %w[new_section request session environment backtrace],
222
+ 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
+ )
226
+
227
+ @controller = HomeController.new
228
+ @controller.process(:index)
229
+
230
+ @test_env = Rack::MockRequest.env_for(
231
+ '/',
232
+ 'HTTP_HOST' => 'test.address',
233
+ 'REMOTE_ADDR' => '127.0.0.1',
234
+ 'HTTP_USER_AGENT' => 'Rails Testing',
235
+ 'action_dispatch.parameter_filter' => ['secret'],
236
+ 'HTTPS' => 'on',
237
+ 'action_controller.instance' => @controller,
238
+ params: { id: 'foo', secret: 'secret' }
239
+ )
240
+
241
+ @mail = @email_notifier.call(@exception, env: @test_env, data: { message: 'My Custom Message' })
242
+ end
243
+
244
+ test 'sends mail with correct content' do
245
+ assert_equal %("Dummy Notifier" <dummynotifier@example.com>), @mail[:from].value
246
+ assert_equal %w[dummyexceptions@example.com], @mail.to
247
+ assert_equal '[Dummy ERROR] home index (ZeroDivisionError) "divided by 0"', @mail.subject
248
+ assert_equal 'foobar', @mail['X-Custom-Header'].value
249
+ assert_equal 'text/plain; charset=UTF-8', @mail.content_type
250
+ assert_equal [], @mail.attachments
251
+
252
+ body = <<-BODY.gsub(/^ /, '')
253
+ A ZeroDivisionError occurred in home#index:
254
+
255
+ divided by 0
256
+ test/exception_notifier/email_notifier_test.rb:20
257
+
258
+
259
+ -------------------------------
260
+ New section:
261
+ -------------------------------
262
+
263
+ * New text section for testing
264
+
265
+ -------------------------------
266
+ Request:
267
+ -------------------------------
268
+
269
+ * URL : https://test.address/?id=foo&secret=secret
270
+ * HTTP Method: GET
271
+ * IP address : 127.0.0.1
272
+ * Parameters : {\"id\"=>\"foo\", \"secret\"=>\"[FILTERED]\"}
273
+ * Timestamp : Sat, 20 Apr 2013 20:58:55 UTC +00:00
274
+ * Server : #{Socket.gethostname}
275
+ BODY
276
+
277
+ body << " * Rails root : #{Rails.root}\n" if defined?(Rails) && Rails.respond_to?(:root)
278
+
279
+ body << <<-BODY.gsub(/^ /, '')
280
+ * Process: #{Process.pid}
281
+
282
+ -------------------------------
283
+ Session:
284
+ -------------------------------
285
+
286
+ * session id: [FILTERED]
287
+ * data: {}
288
+
289
+ -------------------------------
290
+ Environment:
291
+ -------------------------------
292
+
293
+ * CONTENT_LENGTH : 0
294
+ * HTTPS : on
295
+ * HTTP_HOST : test.address
296
+ * HTTP_USER_AGENT : Rails Testing
297
+ * PATH_INFO : /
298
+ * QUERY_STRING : id=foo&secret=secret
299
+ * REMOTE_ADDR : 127.0.0.1
300
+ * REQUEST_METHOD : GET
301
+ * SCRIPT_NAME :
302
+ * SERVER_NAME : example.org
303
+ * SERVER_PORT : 80
304
+ * action_controller.instance : #{@controller}
305
+ * action_dispatch.parameter_filter : [\"secret\"]
306
+ * action_dispatch.request.content_type :
307
+ * action_dispatch.request.parameters : {"id"=>"foo", "secret"=>"[FILTERED]"}
308
+ * action_dispatch.request.path_parameters : {}
309
+ * action_dispatch.request.query_parameters : {"id"=>"foo", "secret"=>"[FILTERED]"}
310
+ * action_dispatch.request.request_parameters: {}
311
+ * rack.errors : #{@test_env['rack.errors']}
312
+ * rack.input : #{@test_env['rack.input']}
313
+ * rack.multiprocess : true
314
+ * rack.multithread : true
315
+ * rack.request.query_hash : {"id"=>"foo", "secret"=>"[FILTERED]"}
316
+ * rack.request.query_string : id=foo&secret=secret
317
+ * rack.run_once : false
318
+ * rack.session : {}
319
+ * rack.url_scheme : http
320
+ * rack.version : #{Rack::VERSION}
321
+
322
+ -------------------------------
323
+ Backtrace:
324
+ -------------------------------
325
+
326
+ test/exception_notifier/email_notifier_test.rb:20
327
+
328
+ -------------------------------
329
+ Data:
330
+ -------------------------------
331
+
332
+ * data: {:message=>\"My Custom Message\"}
333
+
334
+
335
+ BODY
336
+
337
+ assert_equal body, @mail.decode_body
338
+ end
339
+
340
+ test 'should not include controller and action names in subject' do
341
+ email_notifier = ExceptionNotifier::EmailNotifier.new(
342
+ sender_address: %("Dummy Notifier" <dummynotifier@example.com>),
343
+ exception_recipients: %w[dummyexceptions@example.com],
344
+ include_controller_and_action_names_in_subject: false
345
+ )
346
+
347
+ mail = email_notifier.call(@exception, env: @test_env)
348
+
349
+ assert_equal '[ERROR] (ZeroDivisionError) "divided by 0"', mail.subject
350
+ end
351
+ end
@@ -0,0 +1,181 @@
1
+ require 'test_helper'
2
+ require 'rack'
3
+ require 'httparty'
4
+ require 'timecop'
5
+ require 'json'
6
+
7
+ class GoogleChatNotifierTest < ActiveSupport::TestCase
8
+ URL = 'http://localhost:8000'.freeze
9
+
10
+ def setup
11
+ Timecop.freeze('2018-12-09 12:07:16 UTC')
12
+ end
13
+
14
+ def teardown
15
+ Timecop.return
16
+ end
17
+
18
+ test 'should send notification if properly configured' do
19
+ HTTParty.expects(:post).with(URL, post_opts("#{header}\n#{body}"))
20
+ notifier.call ArgumentError.new('foo')
21
+ end
22
+
23
+ test 'shoud use errors count if accumulated_errors_count is provided' do
24
+ text = [
25
+ '',
26
+ "Application: *#{app_name}*",
27
+ '5 *ArgumentError* occurred.',
28
+ '',
29
+ body
30
+ ].join("\n")
31
+
32
+ HTTParty.expects(:post).with(URL, post_opts(text))
33
+
34
+ notifier.call(ArgumentError.new('foo'), accumulated_errors_count: 5)
35
+ end
36
+
37
+ test 'Message request should be formatted as hash' do
38
+ text = [
39
+ header,
40
+ body,
41
+ '',
42
+ '*Request:*',
43
+ '```',
44
+ '* url : http://test.address/?id=foo',
45
+ '* http_method : GET',
46
+ '* ip_address : 127.0.0.1',
47
+ '* parameters : {"id"=>"foo"}',
48
+ '* timestamp : 2018-12-09 12:07:16 UTC',
49
+ '```'
50
+ ].join("\n")
51
+
52
+ HTTParty.expects(:post).with(URL, post_opts(text))
53
+
54
+ notifier.call(ArgumentError.new('foo'), env: test_env)
55
+ end
56
+
57
+ test 'backtrace with less than 3 lines should be displayed fully' do
58
+ text = [
59
+ header,
60
+ body,
61
+ '',
62
+ '*Backtrace:*',
63
+ '```',
64
+ "* app/controllers/my_controller.rb:53:in `my_controller_params'",
65
+ "* app/controllers/my_controller.rb:34:in `update'",
66
+ '```'
67
+ ].join("\n")
68
+
69
+ HTTParty.expects(:post).with(URL, post_opts(text))
70
+
71
+ exception = ArgumentError.new('foo')
72
+ exception.set_backtrace([
73
+ "app/controllers/my_controller.rb:53:in `my_controller_params'",
74
+ "app/controllers/my_controller.rb:34:in `update'"
75
+ ])
76
+
77
+ notifier.call(exception)
78
+ end
79
+
80
+ test 'backtrace with more than 3 lines should display only top 3 lines' do
81
+ text = [
82
+ header,
83
+ body,
84
+ '',
85
+ '*Backtrace:*',
86
+ '```',
87
+ "* app/controllers/my_controller.rb:99:in `specific_function'",
88
+ "* app/controllers/my_controller.rb:70:in `specific_param'",
89
+ "* app/controllers/my_controller.rb:53:in `my_controller_params'",
90
+ '```'
91
+ ].join("\n")
92
+
93
+ HTTParty.expects(:post).with(URL, post_opts(text))
94
+
95
+ exception = ArgumentError.new('foo')
96
+ exception.set_backtrace([
97
+ "app/controllers/my_controller.rb:99:in `specific_function'",
98
+ "app/controllers/my_controller.rb:70:in `specific_param'",
99
+ "app/controllers/my_controller.rb:53:in `my_controller_params'",
100
+ "app/controllers/my_controller.rb:34:in `update'"
101
+ ])
102
+
103
+ notifier.call(exception)
104
+ end
105
+
106
+ test 'Get text with backtrace and request info' do
107
+ text = [
108
+ header,
109
+ body,
110
+ '',
111
+ '*Request:*',
112
+ '```',
113
+ '* url : http://test.address/?id=foo',
114
+ '* http_method : GET',
115
+ '* ip_address : 127.0.0.1',
116
+ '* parameters : {"id"=>"foo"}',
117
+ '* timestamp : 2018-12-09 12:07:16 UTC',
118
+ '```',
119
+ '',
120
+ '*Backtrace:*',
121
+ '```',
122
+ "* app/controllers/my_controller.rb:53:in `my_controller_params'",
123
+ "* app/controllers/my_controller.rb:34:in `update'",
124
+ '```'
125
+ ].join("\n")
126
+
127
+ HTTParty.expects(:post).with(URL, post_opts(text))
128
+
129
+ exception = ArgumentError.new('foo')
130
+ exception.set_backtrace([
131
+ "app/controllers/my_controller.rb:53:in `my_controller_params'",
132
+ "app/controllers/my_controller.rb:34:in `update'"
133
+ ])
134
+
135
+ notifier.call(exception, env: test_env)
136
+ end
137
+
138
+ private
139
+
140
+ def notifier
141
+ ExceptionNotifier::GoogleChatNotifier.new(webhook_url: URL)
142
+ end
143
+
144
+ def post_opts(text)
145
+ {
146
+ body: { text: text }.to_json,
147
+ headers: { 'Content-Type' => 'application/json' }
148
+ }
149
+ end
150
+
151
+ def test_env
152
+ Rack::MockRequest.env_for(
153
+ '/',
154
+ 'HTTP_HOST' => 'test.address',
155
+ 'REMOTE_ADDR' => '127.0.0.1',
156
+ 'HTTP_USER_AGENT' => 'Rails Testing',
157
+ params: { id: 'foo' }
158
+ )
159
+ end
160
+
161
+ def header
162
+ [
163
+ '',
164
+ "Application: *#{app_name}*",
165
+ 'An *ArgumentError* occurred.',
166
+ ''
167
+ ].join("\n")
168
+ end
169
+
170
+ def body
171
+ if defined?(::Rails) && ::Rails.respond_to?(:env)
172
+ "⚠️ Error occurred in test ⚠️\n*foo*"
173
+ else
174
+ "⚠️ Error occurred ⚠️\n*foo*"
175
+ end
176
+ end
177
+
178
+ def app_name
179
+ 'dummy' if defined?(::Rails) && ::Rails.respond_to?(:application)
180
+ end
181
+ end