exception_notification 4.6.0 → 5.0.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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.rdoc +30 -0
  3. data/CONTRIBUTING.md +23 -51
  4. data/README.md +65 -31
  5. data/Rakefile +14 -7
  6. data/exception_notification.gemspec +36 -32
  7. data/lib/exception_notification/rack.rb +4 -4
  8. data/lib/exception_notification/rails.rb +2 -2
  9. data/lib/exception_notification/rake.rb +3 -7
  10. data/lib/exception_notification/resque.rb +2 -2
  11. data/lib/exception_notification/sidekiq.rb +8 -23
  12. data/lib/exception_notification/version.rb +1 -1
  13. data/lib/exception_notification.rb +3 -3
  14. data/lib/exception_notifier/datadog_notifier.rb +26 -26
  15. data/lib/exception_notifier/email_notifier.rb +34 -30
  16. data/lib/exception_notifier/google_chat_notifier.rb +9 -9
  17. data/lib/exception_notifier/hipchat_notifier.rb +12 -12
  18. data/lib/exception_notifier/irc_notifier.rb +6 -6
  19. data/lib/exception_notifier/mattermost_notifier.rb +13 -13
  20. data/lib/exception_notifier/modules/error_grouping.rb +5 -5
  21. data/lib/exception_notifier/modules/formatter.rb +12 -12
  22. data/lib/exception_notifier/notifier.rb +3 -3
  23. data/lib/exception_notifier/slack_notifier.rb +16 -16
  24. data/lib/exception_notifier/sns_notifier.rb +9 -9
  25. data/lib/exception_notifier/teams_notifier.rb +61 -57
  26. data/lib/exception_notifier/webhook_notifier.rb +3 -3
  27. data/lib/exception_notifier.rb +27 -26
  28. data/lib/generators/exception_notification/install_generator.rb +7 -7
  29. data/lib/generators/exception_notification/templates/exception_notification.rb.erb +26 -27
  30. metadata +41 -110
  31. data/Appraisals +0 -9
  32. data/Gemfile +0 -5
  33. data/Gemfile.lock +0 -352
  34. data/gemfiles/rails5_2.gemfile +0 -7
  35. data/gemfiles/rails6_0.gemfile +0 -7
  36. data/gemfiles/rails6_1.gemfile +0 -7
  37. data/gemfiles/rails7_0.gemfile +0 -7
  38. data/test/exception_notification/rack_test.rb +0 -106
  39. data/test/exception_notification/rake_test.rb +0 -38
  40. data/test/exception_notification/resque_test.rb +0 -54
  41. data/test/exception_notifier/datadog_notifier_test.rb +0 -153
  42. data/test/exception_notifier/email_notifier_test.rb +0 -351
  43. data/test/exception_notifier/google_chat_notifier_test.rb +0 -185
  44. data/test/exception_notifier/hipchat_notifier_test.rb +0 -218
  45. data/test/exception_notifier/irc_notifier_test.rb +0 -139
  46. data/test/exception_notifier/mattermost_notifier_test.rb +0 -251
  47. data/test/exception_notifier/modules/error_grouping_test.rb +0 -167
  48. data/test/exception_notifier/modules/formatter_test.rb +0 -152
  49. data/test/exception_notifier/sidekiq_test.rb +0 -34
  50. data/test/exception_notifier/slack_notifier_test.rb +0 -229
  51. data/test/exception_notifier/sns_notifier_test.rb +0 -178
  52. data/test/exception_notifier/teams_notifier_test.rb +0 -92
  53. data/test/exception_notifier/webhook_notifier_test.rb +0 -98
  54. data/test/exception_notifier_test.rb +0 -288
  55. data/test/support/exception_notifier_helper.rb +0 -14
  56. data/test/support/views/exception_notifier/_new_bkg_section.html.erb +0 -1
  57. data/test/support/views/exception_notifier/_new_bkg_section.text.erb +0 -1
  58. data/test/support/views/exception_notifier/_new_section.html.erb +0 -1
  59. data/test/support/views/exception_notifier/_new_section.text.erb +0 -1
  60. data/test/test_helper.rb +0 -19
@@ -1,185 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
- require 'rack'
5
- require 'httparty'
6
- require 'timecop'
7
- require 'json'
8
-
9
- class GoogleChatNotifierTest < ActiveSupport::TestCase
10
- URL = 'http://localhost:8000'
11
-
12
- def setup
13
- Timecop.freeze('2018-12-09 12:07:16 UTC')
14
- end
15
-
16
- def teardown
17
- Timecop.return
18
- end
19
-
20
- test 'should send notification if properly configured' do
21
- HTTParty.expects(:post).with(URL, post_opts("#{header}\n#{body}"))
22
- notifier.call ArgumentError.new('foo')
23
- end
24
-
25
- test 'shoud use errors count if accumulated_errors_count is provided' do
26
- text = [
27
- '',
28
- "Application: *#{app_name}*",
29
- '5 *ArgumentError* occurred.',
30
- '',
31
- body
32
- ].join("\n")
33
-
34
- HTTParty.expects(:post).with(URL, post_opts(text))
35
-
36
- notifier.call(ArgumentError.new('foo'), accumulated_errors_count: 5)
37
- end
38
-
39
- test 'Message request should be formatted as hash' do
40
- text = [
41
- header,
42
- body,
43
- '',
44
- '*Request:*',
45
- '```',
46
- '* url : http://test.address/?id=foo',
47
- '* http_method : GET',
48
- '* ip_address : 127.0.0.1',
49
- '* parameters : {"id"=>"foo"}',
50
- '* timestamp : 2018-12-09 12:07:16 UTC',
51
- '```'
52
- ].join("\n")
53
-
54
- HTTParty.expects(:post).with(URL, post_opts(text))
55
-
56
- notifier.call(ArgumentError.new('foo'), env: test_env)
57
- end
58
-
59
- test 'backtrace with less than 3 lines should be displayed fully' do
60
- text = [
61
- header,
62
- body,
63
- '',
64
- backtrace
65
- ].join("\n")
66
-
67
- HTTParty.expects(:post).with(URL, post_opts(text))
68
-
69
- exception = ArgumentError.new('foo')
70
- exception.set_backtrace([
71
- "app/controllers/my_controller.rb:53:in `my_controller_params'",
72
- "app/controllers/my_controller.rb:34:in `update'"
73
- ])
74
-
75
- notifier.call(exception)
76
- end
77
-
78
- test 'backtrace with more than 3 lines should display only top 3 lines' do
79
- text = [
80
- header,
81
- body,
82
- '',
83
- '*Backtrace:*',
84
- '```',
85
- "* app/controllers/my_controller.rb:99:in `specific_function'",
86
- "* app/controllers/my_controller.rb:70:in `specific_param'",
87
- "* app/controllers/my_controller.rb:53:in `my_controller_params'",
88
- '```'
89
- ].join("\n")
90
-
91
- HTTParty.expects(:post).with(URL, post_opts(text))
92
-
93
- exception = ArgumentError.new('foo')
94
- exception.set_backtrace([
95
- "app/controllers/my_controller.rb:99:in `specific_function'",
96
- "app/controllers/my_controller.rb:70:in `specific_param'",
97
- "app/controllers/my_controller.rb:53:in `my_controller_params'",
98
- "app/controllers/my_controller.rb:34:in `update'"
99
- ])
100
-
101
- notifier.call(exception)
102
- end
103
-
104
- test 'Get text with backtrace and request info' do
105
- text = [
106
- header,
107
- body,
108
- '',
109
- '*Request:*',
110
- '```',
111
- '* url : http://test.address/?id=foo',
112
- '* http_method : GET',
113
- '* ip_address : 127.0.0.1',
114
- '* parameters : {"id"=>"foo"}',
115
- '* timestamp : 2018-12-09 12:07:16 UTC',
116
- '```',
117
- '',
118
- backtrace
119
- ].join("\n")
120
-
121
- HTTParty.expects(:post).with(URL, post_opts(text))
122
-
123
- exception = ArgumentError.new('foo')
124
- exception.set_backtrace([
125
- "app/controllers/my_controller.rb:53:in `my_controller_params'",
126
- "app/controllers/my_controller.rb:34:in `update'"
127
- ])
128
-
129
- notifier.call(exception, env: test_env)
130
- end
131
-
132
- private
133
-
134
- def notifier
135
- ExceptionNotifier::GoogleChatNotifier.new(webhook_url: URL)
136
- end
137
-
138
- def post_opts(text)
139
- {
140
- body: { text: text }.to_json,
141
- headers: { 'Content-Type' => 'application/json' }
142
- }
143
- end
144
-
145
- def test_env
146
- Rack::MockRequest.env_for(
147
- '/',
148
- 'HTTP_HOST' => 'test.address',
149
- 'REMOTE_ADDR' => '127.0.0.1',
150
- 'HTTP_USER_AGENT' => 'Rails Testing',
151
- params: { id: 'foo' }
152
- )
153
- end
154
-
155
- def header
156
- [
157
- '',
158
- "Application: *#{app_name}*",
159
- 'An *ArgumentError* occurred.',
160
- ''
161
- ].join("\n")
162
- end
163
-
164
- def body
165
- if defined?(::Rails) && ::Rails.respond_to?(:env)
166
- "⚠️ Error occurred in test ⚠️\n*foo*"
167
- else
168
- "⚠️ Error occurred ⚠️\n*foo*"
169
- end
170
- end
171
-
172
- def app_name
173
- 'dummy' if defined?(::Rails) && ::Rails.respond_to?(:application)
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
185
- end
@@ -1,218 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
- require 'rack'
5
- require 'hipchat'
6
-
7
- class HipchatNotifierTest < ActiveSupport::TestCase
8
- test 'should send hipchat notification if properly configured' do
9
- options = {
10
- api_token: 'good_token',
11
- room_name: 'room_name',
12
- color: 'yellow'
13
- }
14
-
15
- HipChat::Room.any_instance.expects(:send).with('Exception', fake_body, color: 'yellow')
16
-
17
- hipchat = ExceptionNotifier::HipchatNotifier.new(options)
18
- hipchat.call(fake_exception)
19
- end
20
-
21
- test 'should call pre/post_callback if specified' do
22
- pre_callback_called = 0
23
- post_callback_called = 0
24
- options = {
25
- api_token: 'good_token',
26
- room_name: 'room_name',
27
- color: 'yellow',
28
- pre_callback: proc { |*| pre_callback_called += 1 },
29
- post_callback: proc { |*| post_callback_called += 1 }
30
- }
31
-
32
- HipChat::Room.any_instance
33
- .expects(:send)
34
- .with('Exception', fake_body, { color: 'yellow' }.merge(options.except(:api_token, :room_name)))
35
-
36
- hipchat = ExceptionNotifier::HipchatNotifier.new(options)
37
- hipchat.call(fake_exception)
38
- assert_equal(1, pre_callback_called)
39
- assert_equal(1, post_callback_called)
40
- end
41
-
42
- test 'should send hipchat notification without backtrace info if properly configured' do
43
- options = {
44
- api_token: 'good_token',
45
- room_name: 'room_name',
46
- color: 'yellow'
47
- }
48
-
49
- HipChat::Room.any_instance.expects(:send).with('Exception', fake_body_without_backtrace, color: 'yellow')
50
-
51
- hipchat = ExceptionNotifier::HipchatNotifier.new(options)
52
- hipchat.call(fake_exception_without_backtrace)
53
- end
54
-
55
- test 'should allow custom from value if set' do
56
- options = {
57
- api_token: 'good_token',
58
- room_name: 'room_name',
59
- from: 'TrollFace'
60
- }
61
-
62
- HipChat::Room.any_instance.expects(:send).with('TrollFace', fake_body, color: 'red')
63
-
64
- hipchat = ExceptionNotifier::HipchatNotifier.new(options)
65
- hipchat.call(fake_exception)
66
- end
67
-
68
- test 'should not send hipchat notification if badly configured' do
69
- wrong_params = {
70
- api_token: 'bad_token',
71
- room_name: 'test_room'
72
- }
73
-
74
- HipChat::Client.stubs(:new).with('bad_token', api_version: 'v1').returns(nil)
75
-
76
- hipchat = ExceptionNotifier::HipchatNotifier.new(wrong_params)
77
- assert_nil hipchat.room
78
- end
79
-
80
- test 'should not send hipchat notification if api_key is missing' do
81
- wrong_params = { room_name: 'test_room' }
82
-
83
- HipChat::Client.stubs(:new).with(nil, api_version: 'v1').returns(nil)
84
-
85
- hipchat = ExceptionNotifier::HipchatNotifier.new(wrong_params)
86
- assert_nil hipchat.room
87
- end
88
-
89
- test 'should not send hipchat notification if room_name is missing' do
90
- wrong_params = { api_token: 'good_token' }
91
-
92
- HipChat::Client.stubs(:new).with('good_token', api_version: 'v1').returns({})
93
-
94
- hipchat = ExceptionNotifier::HipchatNotifier.new(wrong_params)
95
- assert_nil hipchat.room
96
- end
97
-
98
- test 'should send hipchat notification with message_template' do
99
- options = {
100
- api_token: 'good_token',
101
- room_name: 'room_name',
102
- color: 'yellow',
103
- message_template: ->(exception, _) { "This is custom message: '#{exception.message}'" }
104
- }
105
-
106
- HipChat::Room.any_instance
107
- .expects(:send)
108
- .with('Exception', "This is custom message: '#{fake_exception.message}'", color: 'yellow')
109
-
110
- hipchat = ExceptionNotifier::HipchatNotifier.new(options)
111
- hipchat.call(fake_exception)
112
- end
113
-
114
- test 'should send hipchat notification exclude accumulated errors count' do
115
- options = {
116
- api_token: 'good_token',
117
- room_name: 'room_name',
118
- color: 'yellow'
119
- }
120
-
121
- HipChat::Room.any_instance.expects(:send).with { |_, msg, _| msg.start_with?('A new exception occurred:') }
122
- hipchat = ExceptionNotifier::HipchatNotifier.new(options)
123
- hipchat.call(fake_exception)
124
- end
125
-
126
- test 'should send hipchat notification include accumulated errors count' do
127
- options = {
128
- api_token: 'good_token',
129
- room_name: 'room_name',
130
- color: 'yellow'
131
- }
132
-
133
- HipChat::Room.any_instance.expects(:send).with { |_, msg, _| msg.start_with?('The exception occurred 3 times:') }
134
- hipchat = ExceptionNotifier::HipchatNotifier.new(options)
135
- hipchat.call(fake_exception, accumulated_errors_count: 3)
136
- end
137
-
138
- test 'should send hipchat notification with HTML-escaped meessage if using default message_template' do
139
- options = {
140
- api_token: 'good_token',
141
- room_name: 'room_name',
142
- color: 'yellow'
143
- }
144
-
145
- exception = fake_exception_with_html_characters
146
- body = "A new exception occurred: '#{Rack::Utils.escape_html(exception.message)}' on '#{exception.backtrace.first}'"
147
-
148
- HipChat::Room.any_instance.expects(:send).with('Exception', body, color: 'yellow')
149
-
150
- hipchat = ExceptionNotifier::HipchatNotifier.new(options)
151
- hipchat.call(exception)
152
- end
153
-
154
- test 'should use APIv1 if api_version is not specified' do
155
- options = {
156
- api_token: 'good_token',
157
- room_name: 'room_name'
158
- }
159
-
160
- HipChat::Client.stubs(:new).with('good_token', api_version: 'v1').returns({})
161
-
162
- hipchat = ExceptionNotifier::HipchatNotifier.new(options)
163
- hipchat.call(fake_exception)
164
- end
165
-
166
- test 'should use APIv2 when specified' do
167
- options = {
168
- api_token: 'good_token',
169
- room_name: 'room_name',
170
- api_version: 'v2'
171
- }
172
-
173
- HipChat::Client.stubs(:new).with('good_token', api_version: 'v2').returns({})
174
-
175
- hipchat = ExceptionNotifier::HipchatNotifier.new(options)
176
- hipchat.call(fake_exception)
177
- end
178
-
179
- test 'should allow server_url value (for a self-hosted HipChat Server) if set' do
180
- options = {
181
- api_token: 'good_token',
182
- room_name: 'room_name',
183
- api_version: 'v2',
184
- server_url: 'https://domain.com'
185
- }
186
-
187
- HipChat::Client.stubs(:new).with('good_token', api_version: 'v2', server_url: 'https://domain.com').returns({})
188
-
189
- hipchat = ExceptionNotifier::HipchatNotifier.new(options)
190
- hipchat.call(fake_exception)
191
- end
192
-
193
- private
194
-
195
- def fake_body
196
- "A new exception occurred: '#{fake_exception.message}' on '#{fake_exception.backtrace.first}'"
197
- end
198
-
199
- def fake_exception
200
- 5 / 0
201
- rescue StandardError => e
202
- e
203
- end
204
-
205
- def fake_exception_with_html_characters
206
- raise StandardError, 'an error with <html> characters'
207
- rescue StandardError => e
208
- e
209
- end
210
-
211
- def fake_body_without_backtrace
212
- "A new exception occurred: '#{fake_exception_without_backtrace.message}'"
213
- end
214
-
215
- def fake_exception_without_backtrace
216
- StandardError.new('my custom error')
217
- end
218
- end
@@ -1,139 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
- require 'carrier-pigeon'
5
-
6
- class IrcNotifierTest < ActiveSupport::TestCase
7
- test 'should send irc notification if properly configured' do
8
- options = {
9
- domain: 'irc.example.com'
10
- }
11
-
12
- CarrierPigeon.expects(:send).with(has_key(:uri)) do |v|
13
- /divided by 0/.match(v[:message])
14
- end
15
-
16
- irc = ExceptionNotifier::IrcNotifier.new(options)
17
- irc.call(fake_exception)
18
- end
19
-
20
- test 'should exclude errors count in message if :accumulated_errors_count nil' do
21
- irc = ExceptionNotifier::IrcNotifier.new({})
22
- irc.stubs(:active?).returns(true)
23
-
24
- irc.expects(:send_message).with { |message| message.include?('divided by 0') }.once
25
- irc.call(fake_exception)
26
- end
27
-
28
- test 'should include errors count in message if :accumulated_errors_count is 3' do
29
- irc = ExceptionNotifier::IrcNotifier.new({})
30
- irc.stubs(:active?).returns(true)
31
-
32
- irc.expects(:send_message).with { |message| message.include?("(3 times)'divided by 0'") }.once
33
- irc.call(fake_exception, accumulated_errors_count: 3)
34
- end
35
-
36
- test 'should call pre/post_callback if specified' do
37
- pre_callback_called = 0
38
- post_callback_called = 0
39
-
40
- options = {
41
- domain: 'irc.example.com',
42
- pre_callback: proc { |*| pre_callback_called += 1 },
43
- post_callback: proc { |*| post_callback_called += 1 }
44
- }
45
-
46
- CarrierPigeon.expects(:send).with(has_key(:uri)) do |v|
47
- /divided by 0/.match(v[:message])
48
- end
49
-
50
- irc = ExceptionNotifier::IrcNotifier.new(options)
51
- irc.call(fake_exception)
52
- assert_equal(1, pre_callback_called)
53
- assert_equal(1, post_callback_called)
54
- end
55
-
56
- test 'should send irc notification without backtrace info if properly configured' do
57
- options = {
58
- domain: 'irc.example.com'
59
- }
60
-
61
- CarrierPigeon.expects(:send).with(has_key(:uri)) do |v|
62
- /my custom error/.match(v[:message])
63
- end
64
-
65
- irc = ExceptionNotifier::IrcNotifier.new(options)
66
- irc.call(fake_exception_without_backtrace)
67
- end
68
-
69
- test 'should properly construct URI from constituent parts' do
70
- options = {
71
- nick: 'BadNewsBot',
72
- password: 'secret',
73
- domain: 'irc.example.com',
74
- port: 9999,
75
- channel: '#exceptions'
76
- }
77
-
78
- CarrierPigeon.expects(:send).with(has_entry(uri: 'irc://BadNewsBot:secret@irc.example.com:9999/#exceptions'))
79
-
80
- irc = ExceptionNotifier::IrcNotifier.new(options)
81
- irc.call(fake_exception)
82
- end
83
-
84
- test 'should properly add recipients if specified' do
85
- options = {
86
- domain: 'irc.example.com',
87
- recipients: %w[peter michael samir]
88
- }
89
-
90
- CarrierPigeon.expects(:send).with(has_key(:uri)) do |v|
91
- /peter, michael, samir/.match(v[:message])
92
- end
93
-
94
- irc = ExceptionNotifier::IrcNotifier.new(options)
95
- irc.call(fake_exception)
96
- end
97
-
98
- test 'should properly set miscellaneous options' do
99
- options = {
100
- domain: 'irc.example.com',
101
- ssl: true,
102
- join: true,
103
- notice: true,
104
- prefix: '[test notification]'
105
- }
106
-
107
- entries = {
108
- ssl: true,
109
- join: true,
110
- notice: true
111
- }
112
-
113
- CarrierPigeon.expects(:send).with(has_entries(entries)) do |v|
114
- /\[test notification\]/.match(v[:message])
115
- end
116
-
117
- irc = ExceptionNotifier::IrcNotifier.new(options)
118
- irc.call(fake_exception)
119
- end
120
-
121
- test 'should not send irc notification if badly configured' do
122
- wrong_params = { domain: '##scriptkiddie.com###' }
123
- irc = ExceptionNotifier::IrcNotifier.new(wrong_params)
124
-
125
- assert_nil irc.call(fake_exception)
126
- end
127
-
128
- private
129
-
130
- def fake_exception
131
- 5 / 0
132
- rescue StandardError => e
133
- e
134
- end
135
-
136
- def fake_exception_without_backtrace
137
- StandardError.new('my custom error')
138
- end
139
- end