exception_notification 4.6.0 → 5.0.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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.rdoc +16 -0
  3. data/CONTRIBUTING.md +23 -51
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +27 -33
  6. data/README.md +65 -31
  7. data/Rakefile +14 -7
  8. data/exception_notification.gemspec +27 -30
  9. data/gemfiles/pinned_dependencies.gemfile +8 -0
  10. data/gemfiles/rails7_1.gemfile +5 -0
  11. data/gemfiles/rails7_2.gemfile +5 -0
  12. data/gemfiles/rails8_0.gemfile +5 -0
  13. data/lib/exception_notification/rack.rb +4 -4
  14. data/lib/exception_notification/rails.rb +2 -2
  15. data/lib/exception_notification/rake.rb +3 -7
  16. data/lib/exception_notification/resque.rb +2 -2
  17. data/lib/exception_notification/sidekiq.rb +8 -23
  18. data/lib/exception_notification/version.rb +1 -1
  19. data/lib/exception_notification.rb +3 -3
  20. data/lib/exception_notifier/datadog_notifier.rb +26 -26
  21. data/lib/exception_notifier/email_notifier.rb +34 -30
  22. data/lib/exception_notifier/google_chat_notifier.rb +9 -9
  23. data/lib/exception_notifier/hipchat_notifier.rb +12 -12
  24. data/lib/exception_notifier/irc_notifier.rb +6 -6
  25. data/lib/exception_notifier/mattermost_notifier.rb +13 -13
  26. data/lib/exception_notifier/modules/error_grouping.rb +5 -5
  27. data/lib/exception_notifier/modules/formatter.rb +12 -12
  28. data/lib/exception_notifier/notifier.rb +3 -3
  29. data/lib/exception_notifier/slack_notifier.rb +16 -16
  30. data/lib/exception_notifier/sns_notifier.rb +9 -9
  31. data/lib/exception_notifier/teams_notifier.rb +61 -57
  32. data/lib/exception_notifier/webhook_notifier.rb +3 -3
  33. data/lib/exception_notifier.rb +27 -26
  34. data/lib/generators/exception_notification/install_generator.rb +7 -7
  35. data/lib/generators/exception_notification/templates/exception_notification.rb.erb +26 -27
  36. data/test/exception_notification/rack_test.rb +14 -14
  37. data/test/exception_notification/rake_test.rb +13 -13
  38. data/test/exception_notification/resque_test.rb +14 -14
  39. data/test/exception_notifier/datadog_notifier_test.rb +47 -46
  40. data/test/exception_notifier/email_notifier_test.rb +89 -98
  41. data/test/exception_notifier/google_chat_notifier_test.rb +77 -77
  42. data/test/exception_notifier/hipchat_notifier_test.rb +76 -74
  43. data/test/exception_notifier/irc_notifier_test.rb +26 -26
  44. data/test/exception_notifier/mattermost_notifier_test.rb +77 -77
  45. data/test/exception_notifier/modules/error_grouping_test.rb +39 -39
  46. data/test/exception_notifier/modules/formatter_test.rb +51 -49
  47. data/test/exception_notifier/sidekiq_test.rb +17 -10
  48. data/test/exception_notifier/slack_notifier_test.rb +66 -67
  49. data/test/exception_notifier/sns_notifier_test.rb +73 -70
  50. data/test/exception_notifier/teams_notifier_test.rb +33 -33
  51. data/test/exception_notifier/webhook_notifier_test.rb +34 -34
  52. data/test/exception_notifier_test.rb +51 -41
  53. data/test/test_helper.rb +8 -11
  54. metadata +45 -85
  55. data/Appraisals +0 -9
  56. data/gemfiles/rails5_2.gemfile +0 -7
  57. data/gemfiles/rails6_0.gemfile +0 -7
  58. data/gemfiles/rails6_1.gemfile +0 -7
  59. data/gemfiles/rails7_0.gemfile +0 -7
@@ -1,38 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'test_helper'
4
- require 'httparty'
5
- require 'timecop'
6
- require 'json'
3
+ require "test_helper"
4
+ require "httparty"
5
+ require "timecop"
6
+ require "json"
7
7
 
8
8
  class MattermostNotifierTest < ActiveSupport::TestCase
9
- URL = 'http://localhost:8000'
9
+ URL = "http://localhost:8000"
10
10
 
11
11
  def setup
12
- Timecop.freeze('2018-12-09 12:07:16 UTC')
12
+ Timecop.freeze("2018-12-09 12:07:16 UTC")
13
13
  end
14
14
 
15
15
  def teardown
16
16
  Timecop.return
17
17
  end
18
18
 
19
- test 'should send notification if properly configured' do
19
+ test "should send notification if properly configured" do
20
20
  opts = {
21
21
  body: default_body.to_json,
22
22
  headers: default_headers
23
23
  }
24
24
 
25
25
  HTTParty.expects(:post).with(URL, opts)
26
- notifier.call ArgumentError.new('foo')
26
+ notifier.call ArgumentError.new("foo")
27
27
  end
28
28
 
29
- test 'should send notification with create issue link if specified' do
29
+ test "should send notification with create issue link if specified" do
30
30
  body = default_body.merge(
31
31
  text: [
32
- '@channel',
32
+ "@channel",
33
33
  error_occurred_in,
34
- 'An *ArgumentError* occurred.',
35
- '*foo*',
34
+ "An *ArgumentError* occurred.",
35
+ "*foo*",
36
36
  github_link
37
37
  ].join("\n")
38
38
  )
@@ -43,13 +43,13 @@ class MattermostNotifierTest < ActiveSupport::TestCase
43
43
  }
44
44
 
45
45
  HTTParty.expects(:post).with(URL, opts)
46
- notifier.call ArgumentError.new('foo'), git_url: 'github.com/aschen'
46
+ notifier.call ArgumentError.new("foo"), git_url: "github.com/aschen"
47
47
  end
48
48
 
49
- test 'should add username and icon_url params to the notification if specified' do
49
+ test "should add username and icon_url params to the notification if specified" do
50
50
  body = default_body.merge(
51
- username: 'Test Bot',
52
- icon_url: 'http://site.com/icon.png'
51
+ username: "Test Bot",
52
+ icon_url: "http://site.com/icon.png"
53
53
  )
54
54
 
55
55
  opts = {
@@ -59,17 +59,17 @@ class MattermostNotifierTest < ActiveSupport::TestCase
59
59
 
60
60
  HTTParty.expects(:post).with(URL, opts)
61
61
  notifier.call(
62
- ArgumentError.new('foo'),
63
- username: 'Test Bot',
64
- avatar: 'http://site.com/icon.png'
62
+ ArgumentError.new("foo"),
63
+ username: "Test Bot",
64
+ avatar: "http://site.com/icon.png"
65
65
  )
66
66
  end
67
67
 
68
- test 'should add other HTTParty options to params' do
68
+ test "should add other HTTParty options to params" do
69
69
  opts = {
70
70
  basic_auth: {
71
- username: 'clara',
72
- password: 'password'
71
+ username: "clara",
72
+ password: "password"
73
73
  },
74
74
  body: default_body.to_json,
75
75
  headers: default_headers
@@ -77,10 +77,10 @@ class MattermostNotifierTest < ActiveSupport::TestCase
77
77
 
78
78
  HTTParty.expects(:post).with(URL, opts)
79
79
  notifier.call(
80
- ArgumentError.new('foo'),
80
+ ArgumentError.new("foo"),
81
81
  basic_auth: {
82
- username: 'clara',
83
- password: 'password'
82
+ username: "clara",
83
+ password: "password"
84
84
  }
85
85
  )
86
86
  end
@@ -92,16 +92,16 @@ class MattermostNotifierTest < ActiveSupport::TestCase
92
92
  }
93
93
 
94
94
  HTTParty.expects(:post).with(URL, opts)
95
- notifier.call(ArgumentError.new('foo'))
95
+ notifier.call(ArgumentError.new("foo"))
96
96
  end
97
97
 
98
- test 'shoud use direct errors count if :accumulated_errors_count option is 5' do
98
+ test "shoud use direct errors count if :accumulated_errors_count option is 5" do
99
99
  body = default_body.merge(
100
100
  text: [
101
- '@channel',
101
+ "@channel",
102
102
  error_occurred_in,
103
- '5 *ArgumentError* occurred.',
104
- '*foo*'
103
+ "5 *ArgumentError* occurred.",
104
+ "*foo*"
105
105
  ].join("\n")
106
106
  )
107
107
 
@@ -111,15 +111,15 @@ class MattermostNotifierTest < ActiveSupport::TestCase
111
111
  }
112
112
 
113
113
  HTTParty.expects(:post).with(URL, opts)
114
- notifier.call(ArgumentError.new('foo'), accumulated_errors_count: 5)
114
+ notifier.call(ArgumentError.new("foo"), accumulated_errors_count: 5)
115
115
  end
116
116
 
117
- test 'should include backtrace and request info' do
117
+ test "should include backtrace and request info" do
118
118
  body = default_body.merge(text: [
119
- '@channel',
119
+ "@channel",
120
120
  error_occurred_in,
121
- 'An *ArgumentError* occurred.',
122
- '*foo*',
121
+ "An *ArgumentError* occurred.",
122
+ "*foo*",
123
123
  request_info,
124
124
  backtrace_info
125
125
  ].join("\n"))
@@ -131,22 +131,22 @@ class MattermostNotifierTest < ActiveSupport::TestCase
131
131
 
132
132
  HTTParty.expects(:post).with(URL, opts)
133
133
 
134
- exception = ArgumentError.new('foo')
134
+ exception = ArgumentError.new("foo")
135
135
  exception.set_backtrace([
136
- "app/controllers/my_controller.rb:53:in `my_controller_params'",
137
- "app/controllers/my_controller.rb:34:in `update'"
138
- ])
136
+ "app/controllers/my_controller.rb:53:in `my_controller_params'",
137
+ "app/controllers/my_controller.rb:34:in `update'"
138
+ ])
139
139
 
140
140
  notifier.call(exception, env: test_env)
141
141
  end
142
142
 
143
- test 'should include exception_data_info' do
143
+ test "should include exception_data_info" do
144
144
  body = default_body.merge(
145
145
  text: [
146
- '@channel',
146
+ "@channel",
147
147
  error_occurred_in,
148
- 'An *ArgumentError* occurred.',
149
- '*foo*',
148
+ "An *ArgumentError* occurred.",
149
+ "*foo*",
150
150
  request_info,
151
151
  exception_data_info
152
152
  ].join("\n")
@@ -158,11 +158,11 @@ class MattermostNotifierTest < ActiveSupport::TestCase
158
158
  }
159
159
 
160
160
  env = test_env.merge(
161
- 'exception_notifier.exception_data' => { foo: 'bar', john: 'doe' }
161
+ "exception_notifier.exception_data" => {foo: "bar", john: "doe"}
162
162
  )
163
163
 
164
164
  HTTParty.expects(:post).with(URL, opts)
165
- notifier.call(ArgumentError.new('foo'), env: env)
165
+ notifier.call(ArgumentError.new("foo"), env: env)
166
166
  end
167
167
 
168
168
  private
@@ -174,78 +174,78 @@ class MattermostNotifierTest < ActiveSupport::TestCase
174
174
  def default_body
175
175
  {
176
176
  text: [
177
- '@channel',
177
+ "@channel",
178
178
  error_occurred_in,
179
- 'An *ArgumentError* occurred.',
180
- '*foo*'
179
+ "An *ArgumentError* occurred.",
180
+ "*foo*"
181
181
  ].join("\n"),
182
- username: 'Exception Notifier'
182
+ username: "Exception Notifier"
183
183
  }
184
184
  end
185
185
 
186
186
  def default_headers
187
- { 'Content-Type' => 'application/json' }
187
+ {"Content-Type" => "application/json"}
188
188
  end
189
189
 
190
190
  def test_env
191
191
  Rack::MockRequest.env_for(
192
- '/',
193
- 'HTTP_HOST' => 'test.address',
194
- 'REMOTE_ADDR' => '127.0.0.1',
195
- 'HTTP_USER_AGENT' => 'Rails Testing',
196
- params: { id: 'foo' }
192
+ "/",
193
+ "HTTP_HOST" => "test.address",
194
+ "REMOTE_ADDR" => "127.0.0.1",
195
+ "HTTP_USER_AGENT" => "Rails Testing",
196
+ :params => {id: "foo"}
197
197
  )
198
198
  end
199
199
 
200
200
  def error_occurred_in
201
201
  if defined?(::Rails) && ::Rails.respond_to?(:env)
202
- '### ⚠️ Error occurred in test ⚠️'
202
+ "### ⚠️ Error occurred in test ⚠️"
203
203
  else
204
- '### ⚠️ Error occurred ⚠️'
204
+ "### ⚠️ Error occurred ⚠️"
205
205
  end
206
206
  end
207
207
 
208
208
  def github_link
209
209
  if defined?(::Rails) && ::Rails.respond_to?(:application)
210
- '[Create an issue]' \
211
- '(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)"
212
212
  else
213
213
  # TODO: fix missing app name
214
- '[Create an issue]' \
215
- '(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)"
216
216
  end
217
217
  end
218
218
 
219
219
  def request_info
220
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
- '```'
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"}}", # standard:disable Lint/LiteralInInterpolation
227
+ "* timestamp : 2018-12-09 12:07:16 UTC",
228
+ "```"
229
229
  ]
230
230
  end
231
231
 
232
232
  def backtrace_info
233
233
  [
234
- '### Backtrace',
235
- '```',
234
+ "### Backtrace",
235
+ "```",
236
236
  "* app/controllers/my_controller.rb:53:in `my_controller_params'",
237
237
  "* app/controllers/my_controller.rb:34:in `update'",
238
- '```'
238
+ "```"
239
239
  ]
240
240
  end
241
241
 
242
242
  def exception_data_info
243
243
  [
244
- '### Data',
245
- '```',
246
- '* foo : bar',
247
- '* john : doe',
248
- '```'
244
+ "### Data",
245
+ "```",
246
+ "* foo : bar",
247
+ "* john : doe",
248
+ "```"
249
249
  ]
250
250
  end
251
251
  end
@@ -1,19 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'test_helper'
3
+ require "test_helper"
4
4
 
5
5
  class ErrorGroupTest < ActiveSupport::TestCase
6
- setup do
7
- module TestModule
8
- include ExceptionNotifier::ErrorGrouping
9
- @@error_grouping_cache = ActiveSupport::Cache::FileStore.new('test/dummy/tmp/non_default_location')
10
- end
6
+ module TestModule
7
+ include ExceptionNotifier::ErrorGrouping
8
+ @@error_grouping_cache = ActiveSupport::Cache::FileStore.new("test/dummy/tmp/non_default_location")
9
+ end
11
10
 
12
- @exception = RuntimeError.new('ERROR')
13
- @exception.stubs(:backtrace).returns(['/path/where/error/raised:1'])
11
+ setup do
12
+ @exception = RuntimeError.new("ERROR")
13
+ @exception.stubs(:backtrace).returns(["/path/where/error/raised:1"])
14
14
 
15
- @exception2 = RuntimeError.new('ERROR2')
16
- @exception2.stubs(:backtrace).returns(['/path/where/error/found:2'])
15
+ @exception2 = RuntimeError.new("ERROR2")
16
+ @exception2.stubs(:backtrace).returns(["/path/where/error/found:2"])
17
17
  end
18
18
 
19
19
  teardown do
@@ -21,86 +21,86 @@ class ErrorGroupTest < ActiveSupport::TestCase
21
21
  TestModule.fallback_cache_store.clear
22
22
  end
23
23
 
24
- test 'should add additional option: error_grouping' do
24
+ test "should add additional option: error_grouping" do
25
25
  assert_respond_to TestModule, :error_grouping
26
26
  assert_respond_to TestModule, :error_grouping=
27
27
  end
28
28
 
29
- test 'should set error_grouping to false default' do
29
+ test "should set error_grouping to false default" do
30
30
  assert_equal false, TestModule.error_grouping
31
31
  end
32
32
 
33
- test 'should add additional option: error_grouping_cache' do
33
+ test "should add additional option: error_grouping_cache" do
34
34
  assert_respond_to TestModule, :error_grouping_cache
35
35
  assert_respond_to TestModule, :error_grouping_cache=
36
36
  end
37
37
 
38
- test 'should add additional option: error_grouping_period' do
38
+ test "should add additional option: error_grouping_period" do
39
39
  assert_respond_to TestModule, :error_grouping_period
40
40
  assert_respond_to TestModule, :error_grouping_period=
41
41
  end
42
42
 
43
- test 'shoud set error_grouping_period to 5.minutes default' do
43
+ test "shoud set error_grouping_period to 5.minutes default" do
44
44
  assert_equal 300, TestModule.error_grouping_period
45
45
  end
46
46
 
47
- test 'should add additional option: notification_trigger' do
47
+ test "should add additional option: notification_trigger" do
48
48
  assert_respond_to TestModule, :notification_trigger
49
49
  assert_respond_to TestModule, :notification_trigger=
50
50
  end
51
51
 
52
- test 'should return errors count nil when not same error for .error_count' do
53
- assert_nil TestModule.error_count('something')
52
+ test "should return errors count nil when not same error for .error_count" do
53
+ assert_nil TestModule.error_count("something")
54
54
  end
55
55
 
56
- test 'should return errors count when same error for .error_count' do
57
- TestModule.error_grouping_cache.write('error_key', 13)
58
- assert_equal 13, TestModule.error_count('error_key')
56
+ test "should return errors count when same error for .error_count" do
57
+ TestModule.error_grouping_cache.write("error_key", 13)
58
+ assert_equal 13, TestModule.error_count("error_key")
59
59
  end
60
60
 
61
- test 'should fallback to memory store cache if specified cache store failed to read' do
62
- TestModule.error_grouping_cache.stubs(:read).raises(RuntimeError.new('Failed to read'))
61
+ test "should fallback to memory store cache if specified cache store failed to read" do
62
+ TestModule.error_grouping_cache.stubs(:read).raises(RuntimeError.new("Failed to read"))
63
63
  original_fallback = TestModule.fallback_cache_store
64
64
  TestModule.expects(:fallback_cache_store).returns(original_fallback).at_least_once
65
65
 
66
- assert_nil TestModule.error_count('something_to_read')
66
+ assert_nil TestModule.error_count("something_to_read")
67
67
  end
68
68
 
69
- test 'should save error with count for .save_error_count' do
69
+ test "should save error with count for .save_error_count" do
70
70
  count = rand(1..10)
71
71
 
72
- TestModule.save_error_count('error_key', count)
73
- assert_equal count, TestModule.error_grouping_cache.read('error_key')
72
+ TestModule.save_error_count("error_key", count)
73
+ assert_equal count, TestModule.error_grouping_cache.read("error_key")
74
74
  end
75
75
 
76
- test 'should fallback to memory store cache if specified cache store failed to write' do
77
- TestModule.error_grouping_cache.stubs(:write).raises(RuntimeError.new('Failed to write'))
76
+ test "should fallback to memory store cache if specified cache store failed to write" do
77
+ TestModule.error_grouping_cache.stubs(:write).raises(RuntimeError.new("Failed to write"))
78
78
  original_fallback = TestModule.fallback_cache_store
79
79
  TestModule.expects(:fallback_cache_store).returns(original_fallback).at_least_once
80
80
 
81
- assert TestModule.save_error_count('something_to_cache', rand(1..10))
81
+ assert TestModule.save_error_count("something_to_cache", rand(1..10))
82
82
  end
83
83
 
84
- test 'should save accumulated_errors_count into options' do
84
+ test "should save accumulated_errors_count into options" do
85
85
  options = {}
86
86
  TestModule.group_error!(@exception, options)
87
87
 
88
88
  assert_equal 1, options[:accumulated_errors_count]
89
89
  end
90
90
 
91
- test 'should not group error if different exception in .group_error!' do
91
+ test "should not group error if different exception in .group_error!" do
92
92
  options1 = {}
93
93
  TestModule.expects(:save_error_count).with { |key, count| key.is_a?(String) && count == 1 }.times(4).returns(true)
94
94
  TestModule.group_error!(@exception, options1)
95
95
 
96
96
  options2 = {}
97
- TestModule.group_error!(NoMethodError.new('method not found'), options2)
97
+ TestModule.group_error!(NoMethodError.new("method not found"), options2)
98
98
 
99
99
  assert_equal 1, options1[:accumulated_errors_count]
100
100
  assert_equal 1, options2[:accumulated_errors_count]
101
101
  end
102
102
 
103
- test 'should not group error is same exception but different message or backtrace' do
103
+ test "should not group error is same exception but different message or backtrace" do
104
104
  options1 = {}
105
105
  TestModule.expects(:save_error_count).with { |key, count| key.is_a?(String) && count == 1 }.times(4).returns(true)
106
106
  TestModule.group_error!(@exception, options1)
@@ -112,7 +112,7 @@ class ErrorGroupTest < ActiveSupport::TestCase
112
112
  assert_equal 1, options2[:accumulated_errors_count]
113
113
  end
114
114
 
115
- test 'should group error if same exception and message' do
115
+ test "should group error if same exception and message" do
116
116
  options = {}
117
117
 
118
118
  10.times do |i|
@@ -123,7 +123,7 @@ class ErrorGroupTest < ActiveSupport::TestCase
123
123
  assert_equal 10, options[:accumulated_errors_count]
124
124
  end
125
125
 
126
- test 'should group error if same exception and backtrace' do
126
+ test "should group error if same exception and backtrace" do
127
127
  options = {}
128
128
 
129
129
  10.times do |i|
@@ -134,7 +134,7 @@ class ErrorGroupTest < ActiveSupport::TestCase
134
134
  assert_equal 10, options[:accumulated_errors_count]
135
135
  end
136
136
 
137
- test 'should group error by that message have high priority' do
137
+ test "should group error by that message have high priority" do
138
138
  message_based_key = "exception:#{Zlib.crc32("RuntimeError\nmessage:ERROR")}"
139
139
  backtrace_based_key = "exception:#{Zlib.crc32("RuntimeError\npath:/path/where/error/raised:1")}"
140
140
 
@@ -147,7 +147,7 @@ class ErrorGroupTest < ActiveSupport::TestCase
147
147
  TestModule.group_error!(@exception, {})
148
148
  end
149
149
 
150
- test 'use default formula if not specify notification_trigger in .send_notification?' do
150
+ test "use default formula if not specify notification_trigger in .send_notification?" do
151
151
  TestModule.stubs(:notification_trigger).returns(nil)
152
152
 
153
153
  count = 16
@@ -156,7 +156,7 @@ class ErrorGroupTest < ActiveSupport::TestCase
156
156
  assert TestModule.send_notification?(@exception, count)
157
157
  end
158
158
 
159
- test 'use specified trigger in .send_notification?' do
159
+ test "use specified trigger in .send_notification?" do
160
160
  trigger = proc { |_exception, count| (count % 4).zero? }
161
161
  TestModule.stubs(:notification_trigger).returns(trigger)
162
162