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