exception_notification_more_info 1.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.
- checksums.yaml +7 -0
- data/Appraisals +7 -0
- data/CHANGELOG.rdoc +141 -0
- data/CODE_OF_CONDUCT.md +22 -0
- data/CONTRIBUTING.md +42 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.md +839 -0
- data/Rakefile +23 -0
- data/examples/sinatra/Gemfile +8 -0
- data/examples/sinatra/Gemfile.lock +95 -0
- data/examples/sinatra/Procfile +2 -0
- data/examples/sinatra/README.md +11 -0
- data/examples/sinatra/config.ru +3 -0
- data/examples/sinatra/sinatra_app.rb +32 -0
- data/exception_notification_more_info.gemspec +34 -0
- data/gemfiles/rails4_0.gemfile +7 -0
- data/gemfiles/rails4_1.gemfile +7 -0
- data/gemfiles/rails4_2.gemfile +7 -0
- data/lib/exception_notification.rb +11 -0
- data/lib/exception_notification/rack.rb +59 -0
- data/lib/exception_notification/rails.rb +8 -0
- data/lib/exception_notification/resque.rb +24 -0
- data/lib/exception_notification/sidekiq.rb +31 -0
- data/lib/exception_notifier.rb +121 -0
- data/lib/exception_notifier/base_notifier.rb +25 -0
- data/lib/exception_notifier/campfire_notifier.rb +36 -0
- data/lib/exception_notifier/email_notifier.rb +204 -0
- data/lib/exception_notifier/hipchat_notifier.rb +45 -0
- data/lib/exception_notifier/irc_notifier.rb +51 -0
- data/lib/exception_notifier/modules/backtrace_cleaner.rb +13 -0
- data/lib/exception_notifier/notifier.rb +16 -0
- data/lib/exception_notifier/slack_notifier.rb +73 -0
- data/lib/exception_notifier/views/exception_notifier/_backtrace.html.erb +3 -0
- data/lib/exception_notifier/views/exception_notifier/_backtrace.text.erb +1 -0
- data/lib/exception_notifier/views/exception_notifier/_data.html.erb +6 -0
- data/lib/exception_notifier/views/exception_notifier/_data.text.erb +1 -0
- data/lib/exception_notifier/views/exception_notifier/_environment.html.erb +10 -0
- data/lib/exception_notifier/views/exception_notifier/_environment.text.erb +5 -0
- data/lib/exception_notifier/views/exception_notifier/_request.html.erb +36 -0
- data/lib/exception_notifier/views/exception_notifier/_request.text.erb +10 -0
- data/lib/exception_notifier/views/exception_notifier/_session.html.erb +10 -0
- data/lib/exception_notifier/views/exception_notifier/_session.text.erb +2 -0
- data/lib/exception_notifier/views/exception_notifier/_title.html.erb +3 -0
- data/lib/exception_notifier/views/exception_notifier/_title.text.erb +3 -0
- data/lib/exception_notifier/views/exception_notifier/background_exception_notification.html.erb +53 -0
- data/lib/exception_notifier/views/exception_notifier/background_exception_notification.text.erb +14 -0
- data/lib/exception_notifier/views/exception_notifier/exception_notification.html.erb +54 -0
- data/lib/exception_notifier/views/exception_notifier/exception_notification.text.erb +24 -0
- data/lib/exception_notifier/webhook_notifier.rb +47 -0
- data/lib/generators/exception_notification/install_generator.rb +15 -0
- data/lib/generators/exception_notification/templates/exception_notification.rb +53 -0
- data/test/dummy/.gitignore +4 -0
- data/test/dummy/Gemfile +34 -0
- data/test/dummy/Gemfile.lock +137 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/posts_controller.rb +30 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/helpers/posts_helper.rb +2 -0
- data/test/dummy/app/models/post.rb +2 -0
- data/test/dummy/app/views/exception_notifier/_new_bkg_section.html.erb +1 -0
- data/test/dummy/app/views/exception_notifier/_new_bkg_section.text.erb +1 -0
- data/test/dummy/app/views/exception_notifier/_new_section.html.erb +1 -0
- data/test/dummy/app/views/exception_notifier/_new_section.text.erb +1 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- 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 +4 -0
- data/test/dummy/config/application.rb +42 -0
- data/test/dummy/config/boot.rb +6 -0
- data/test/dummy/config/database.yml +22 -0
- data/test/dummy/config/environment.rb +17 -0
- data/test/dummy/config/environments/development.rb +25 -0
- data/test/dummy/config/environments/production.rb +50 -0
- data/test/dummy/config/environments/test.rb +38 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +8 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/db/migrate/20110729022608_create_posts.rb +15 -0
- data/test/dummy/db/schema.rb +24 -0
- data/test/dummy/db/seeds.rb +7 -0
- data/test/dummy/lib/tasks/.gitkeep +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/public/images/rails.png +0 -0
- data/test/dummy/public/index.html +239 -0
- data/test/dummy/public/javascripts/application.js +2 -0
- data/test/dummy/public/javascripts/controls.js +965 -0
- data/test/dummy/public/javascripts/dragdrop.js +974 -0
- data/test/dummy/public/javascripts/effects.js +1123 -0
- data/test/dummy/public/javascripts/prototype.js +6001 -0
- data/test/dummy/public/javascripts/rails.js +191 -0
- data/test/dummy/public/robots.txt +5 -0
- data/test/dummy/public/stylesheets/.gitkeep +0 -0
- data/test/dummy/public/stylesheets/scaffold.css +56 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/test/fixtures/posts.yml +11 -0
- data/test/dummy/test/functional/posts_controller_test.rb +224 -0
- data/test/dummy/test/test_helper.rb +13 -0
- data/test/exception_notification/rack_test.rb +20 -0
- data/test/exception_notifier/campfire_notifier_test.rb +100 -0
- data/test/exception_notifier/email_notifier_test.rb +185 -0
- data/test/exception_notifier/hipchat_notifier_test.rb +177 -0
- data/test/exception_notifier/irc_notifier_test.rb +121 -0
- data/test/exception_notifier/sidekiq_test.rb +27 -0
- data/test/exception_notifier/slack_notifier_test.rb +179 -0
- data/test/exception_notifier/webhook_notifier_test.rb +68 -0
- data/test/exception_notifier_test.rb +103 -0
- data/test/test_helper.rb +18 -0
- metadata +428 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
require 'carrier-pigeon'
|
|
3
|
+
|
|
4
|
+
class IrcNotifierTest < ActiveSupport::TestCase
|
|
5
|
+
|
|
6
|
+
test "should send irc notification if properly configured" do
|
|
7
|
+
options = {
|
|
8
|
+
:domain => 'irc.example.com'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
CarrierPigeon.expects(:send).with(has_key(:uri)) do |v|
|
|
12
|
+
/divided by 0/.match(v[:message])
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
irc = ExceptionNotifier::IrcNotifier.new(options)
|
|
16
|
+
irc.call(fake_exception)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
test "should call pre/post_callback if specified" do
|
|
20
|
+
pre_callback_called, post_callback_called = 0,0
|
|
21
|
+
|
|
22
|
+
options = {
|
|
23
|
+
:domain => 'irc.example.com',
|
|
24
|
+
:pre_callback => proc { |*| pre_callback_called += 1},
|
|
25
|
+
:post_callback => proc { |*| post_callback_called += 1}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
CarrierPigeon.expects(:send).with(has_key(:uri)) do |v|
|
|
29
|
+
/divided by 0/.match(v[:message])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
irc = ExceptionNotifier::IrcNotifier.new(options)
|
|
33
|
+
irc.call(fake_exception)
|
|
34
|
+
assert_equal(1, pre_callback_called)
|
|
35
|
+
assert_equal(1, post_callback_called)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
test "should send irc notification without backtrace info if properly configured" do
|
|
39
|
+
options = {
|
|
40
|
+
:domain => 'irc.example.com'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
CarrierPigeon.expects(:send).with(has_key(:uri)) do |v|
|
|
44
|
+
/my custom error/.match(v[:message])
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
irc = ExceptionNotifier::IrcNotifier.new(options)
|
|
48
|
+
irc.call(fake_exception_without_backtrace)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
test "should properly construct URI from constituent parts" do
|
|
52
|
+
options = {
|
|
53
|
+
:nick => 'BadNewsBot',
|
|
54
|
+
:password => 'secret',
|
|
55
|
+
:domain => 'irc.example.com',
|
|
56
|
+
:port => 9999,
|
|
57
|
+
:channel => '#exceptions'
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
CarrierPigeon.expects(:send).with(has_entry(uri: "irc://BadNewsBot:secret@irc.example.com:9999/#exceptions"))
|
|
61
|
+
|
|
62
|
+
irc = ExceptionNotifier::IrcNotifier.new(options)
|
|
63
|
+
irc.call(fake_exception)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
test "should properly add recipients if specified" do
|
|
67
|
+
options = {
|
|
68
|
+
domain: 'irc.example.com',
|
|
69
|
+
recipients: ['peter', 'michael', 'samir']
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
CarrierPigeon.expects(:send).with(has_key(:uri)) do |v|
|
|
73
|
+
/peter, michael, samir/.match(v[:message])
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
irc = ExceptionNotifier::IrcNotifier.new(options)
|
|
77
|
+
irc.call(fake_exception)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
test "should properly set miscellaneous options" do
|
|
81
|
+
options = {
|
|
82
|
+
domain: 'irc.example.com',
|
|
83
|
+
ssl: true,
|
|
84
|
+
join: true,
|
|
85
|
+
notice: true,
|
|
86
|
+
prefix: '[test notification]'
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
CarrierPigeon.expects(:send).with(has_entries(
|
|
90
|
+
ssl: true,
|
|
91
|
+
join: true,
|
|
92
|
+
notice: true,
|
|
93
|
+
)) do |v|
|
|
94
|
+
/\[test notification\]/.match(v[:message])
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
irc = ExceptionNotifier::IrcNotifier.new(options)
|
|
98
|
+
irc.call(fake_exception)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
test "should not send irc notification if badly configured" do
|
|
102
|
+
wrong_params = { domain: '##scriptkiddie.com###'}
|
|
103
|
+
irc = ExceptionNotifier::IrcNotifier.new(wrong_params)
|
|
104
|
+
|
|
105
|
+
assert_nil irc.call(fake_exception)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def fake_exception
|
|
111
|
+
exception = begin
|
|
112
|
+
5/0
|
|
113
|
+
rescue Exception => e
|
|
114
|
+
e
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def fake_exception_without_backtrace
|
|
119
|
+
StandardError.new('my custom error')
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require "test_helper"
|
|
2
|
+
|
|
3
|
+
# To allow sidekiq error handlers to be registered, sidekiq must be in
|
|
4
|
+
# "server mode". This mode is triggered by loading sidekiq/cli. Note this
|
|
5
|
+
# has to be loaded before exception_notification/sidekiq.
|
|
6
|
+
require "sidekiq/cli"
|
|
7
|
+
|
|
8
|
+
require "exception_notification/sidekiq"
|
|
9
|
+
|
|
10
|
+
class MockSidekiqServer
|
|
11
|
+
include ::Sidekiq::ExceptionHandler
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class SidekiqTest < ActiveSupport::TestCase
|
|
15
|
+
test "should call notify_exception when sidekiq raises an error" do
|
|
16
|
+
server = MockSidekiqServer.new
|
|
17
|
+
message = Hash.new
|
|
18
|
+
exception = RuntimeError.new
|
|
19
|
+
|
|
20
|
+
ExceptionNotifier.expects(:notify_exception).with(
|
|
21
|
+
exception,
|
|
22
|
+
:data => { :sidekiq => message }
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
server.handle_exception(exception, message)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
require 'slack-notifier'
|
|
3
|
+
|
|
4
|
+
class SlackNotifierTest < ActiveSupport::TestCase
|
|
5
|
+
|
|
6
|
+
def setup
|
|
7
|
+
@exception = fake_exception
|
|
8
|
+
@exception.stubs(:backtrace).returns(fake_backtrace)
|
|
9
|
+
@exception.stubs(:message).returns('exception message')
|
|
10
|
+
Socket.stubs(:gethostname).returns('example.com')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
test "should send a slack notification if properly configured" do
|
|
14
|
+
options = {
|
|
15
|
+
webhook_url: "http://slack.webhook.url"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
Slack::Notifier.any_instance.expects(:ping).with('', fake_notification)
|
|
19
|
+
|
|
20
|
+
slack_notifier = ExceptionNotifier::SlackNotifier.new(options)
|
|
21
|
+
slack_notifier.call(@exception)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
test "should send a slack notification without backtrace info if properly configured" do
|
|
25
|
+
options = {
|
|
26
|
+
webhook_url: "http://slack.webhook.url"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
Slack::Notifier.any_instance.expects(:ping).with('', fake_notification(fake_exception_without_backtrace))
|
|
30
|
+
|
|
31
|
+
slack_notifier = ExceptionNotifier::SlackNotifier.new(options)
|
|
32
|
+
slack_notifier.call(fake_exception_without_backtrace)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
test "should send the notification to the specified channel" do
|
|
36
|
+
options = {
|
|
37
|
+
webhook_url: "http://slack.webhook.url",
|
|
38
|
+
channel: "channel"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
Slack::Notifier.any_instance.expects(:ping).with('', fake_notification)
|
|
42
|
+
|
|
43
|
+
slack_notifier = ExceptionNotifier::SlackNotifier.new(options)
|
|
44
|
+
slack_notifier.call(@exception)
|
|
45
|
+
|
|
46
|
+
assert_equal slack_notifier.notifier.channel, options[:channel]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
test "should send the notification to the specified username" do
|
|
50
|
+
options = {
|
|
51
|
+
webhook_url: "http://slack.webhook.url",
|
|
52
|
+
username: "username"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
Slack::Notifier.any_instance.expects(:ping).with('', fake_notification)
|
|
56
|
+
|
|
57
|
+
slack_notifier = ExceptionNotifier::SlackNotifier.new(options)
|
|
58
|
+
slack_notifier.call(@exception)
|
|
59
|
+
|
|
60
|
+
assert_equal slack_notifier.notifier.username, options[:username]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
test "should pass the additional parameters to Slack::Notifier.ping" do
|
|
64
|
+
options = {
|
|
65
|
+
webhook_url: "http://slack.webhook.url",
|
|
66
|
+
username: "test",
|
|
67
|
+
custom_hook: "hook",
|
|
68
|
+
additional_parameters: {
|
|
69
|
+
icon_url: "icon",
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
Slack::Notifier.any_instance.expects(:ping).with('', options[:additional_parameters].merge(fake_notification) )
|
|
74
|
+
|
|
75
|
+
slack_notifier = ExceptionNotifier::SlackNotifier.new(options)
|
|
76
|
+
slack_notifier.call(@exception)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
test "shouldn't send a slack notification if webhook url is missing" do
|
|
80
|
+
options = {}
|
|
81
|
+
|
|
82
|
+
slack_notifier = ExceptionNotifier::SlackNotifier.new(options)
|
|
83
|
+
|
|
84
|
+
assert_nil slack_notifier.notifier
|
|
85
|
+
assert_nil slack_notifier.call(@exception)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
test "should pass along environment data" do
|
|
89
|
+
options = {
|
|
90
|
+
webhook_url: "http://slack.webhook.url",
|
|
91
|
+
ignore_data_if: lambda {|k,v|
|
|
92
|
+
"#{k}" == 'key_to_be_ignored' || v.is_a?(Hash)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
notification_options = {
|
|
97
|
+
env: {
|
|
98
|
+
'exception_notifier.exception_data' => {foo: 'bar', john: 'doe'}
|
|
99
|
+
},
|
|
100
|
+
data: {
|
|
101
|
+
'user_id' => 5,
|
|
102
|
+
'key_to_be_ignored' => 'whatever',
|
|
103
|
+
'ignore_as_well' => {what: 'ever'}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
expected_data_string = "foo: bar\njohn: doe\nuser_id: 5"
|
|
108
|
+
|
|
109
|
+
Slack::Notifier.any_instance.expects(:ping).with('', fake_notification(@exception, expected_data_string))
|
|
110
|
+
slack_notifier = ExceptionNotifier::SlackNotifier.new(options)
|
|
111
|
+
slack_notifier.call(@exception, notification_options)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
test "should call pre/post_callback proc if specified" do
|
|
115
|
+
post_callback_called = 0
|
|
116
|
+
options = {
|
|
117
|
+
webhook_url: "http://slack.webhook.url",
|
|
118
|
+
username: "test",
|
|
119
|
+
custom_hook: "hook",
|
|
120
|
+
:pre_callback => proc { |opts, notifier, backtrace, message, message_opts|
|
|
121
|
+
(message_opts[:attachments] = []) << { text: "#{backtrace.join("\n")}", color: 'danger' }
|
|
122
|
+
},
|
|
123
|
+
:post_callback => proc { |opts, notifier, backtrace, message, message_opts|
|
|
124
|
+
post_callback_called = 1
|
|
125
|
+
},
|
|
126
|
+
additional_parameters: {
|
|
127
|
+
icon_url: "icon",
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
Slack::Notifier.any_instance.expects(:ping).with('',
|
|
132
|
+
{:icon_url => 'icon',
|
|
133
|
+
:attachments => [
|
|
134
|
+
{:text => fake_backtrace.join("\n"),
|
|
135
|
+
:color => 'danger'}
|
|
136
|
+
]})
|
|
137
|
+
|
|
138
|
+
slack_notifier = ExceptionNotifier::SlackNotifier.new(options)
|
|
139
|
+
slack_notifier.call(@exception)
|
|
140
|
+
assert_equal(post_callback_called, 1)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
private
|
|
144
|
+
|
|
145
|
+
def fake_exception
|
|
146
|
+
begin
|
|
147
|
+
5/0
|
|
148
|
+
rescue Exception => e
|
|
149
|
+
e
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def fake_exception_without_backtrace
|
|
154
|
+
StandardError.new('my custom error')
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def fake_backtrace
|
|
158
|
+
[
|
|
159
|
+
"backtrace line 1",
|
|
160
|
+
"backtrace line 2",
|
|
161
|
+
"backtrace line 3",
|
|
162
|
+
"backtrace line 4",
|
|
163
|
+
"backtrace line 5",
|
|
164
|
+
"backtrace line 6",
|
|
165
|
+
]
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def fake_notification(exception = @exception, data_string = nil)
|
|
169
|
+
text = "*An exception occurred while doing*: ` <>`\n"
|
|
170
|
+
|
|
171
|
+
fields = [ { title: 'Exception', value: exception.message} ]
|
|
172
|
+
fields.push({ title: 'Hostname', value: 'example.com' })
|
|
173
|
+
fields.push({ title: 'Backtrace', value: "```#{fake_backtrace.join("\n")}```" }) if exception.backtrace
|
|
174
|
+
fields.push({ title: 'Data', value: "```#{data_string}```" }) if data_string
|
|
175
|
+
|
|
176
|
+
{ attachments: [ color: 'danger', text: text, fields: fields, mrkdwn_in: %w(text fields) ] }
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
require 'httparty'
|
|
3
|
+
|
|
4
|
+
class WebhookNotifierTest < ActiveSupport::TestCase
|
|
5
|
+
|
|
6
|
+
test "should send webhook notification if properly configured" do
|
|
7
|
+
ExceptionNotifier::WebhookNotifier.stubs(:new).returns(Object.new)
|
|
8
|
+
webhook = ExceptionNotifier::WebhookNotifier.new({:url => 'http://localhost:8000'})
|
|
9
|
+
webhook.stubs(:call).returns(fake_response)
|
|
10
|
+
response = webhook.call(fake_exception)
|
|
11
|
+
|
|
12
|
+
refute_nil response
|
|
13
|
+
assert_equal response[:status], 200
|
|
14
|
+
assert_equal response[:body][:exception][:error_class], "ZeroDivisionError"
|
|
15
|
+
assert_includes response[:body][:exception][:message], "divided by 0"
|
|
16
|
+
assert_includes response[:body][:exception][:backtrace], "/exception_notification/test/webhook_notifier_test.rb:48"
|
|
17
|
+
|
|
18
|
+
assert response[:body][:request][:cookies].has_key?(:cookie_item1)
|
|
19
|
+
assert_equal response[:body][:request][:url], "http://example.com/example"
|
|
20
|
+
assert_equal response[:body][:request][:ip_address], "192.168.1.1"
|
|
21
|
+
assert response[:body][:request][:environment].has_key?(:env_item1)
|
|
22
|
+
assert_equal response[:body][:request][:controller], "#<ControllerName:0x007f9642a04d00>"
|
|
23
|
+
assert response[:body][:request][:session].has_key?(:session_item1)
|
|
24
|
+
assert response[:body][:request][:parameters].has_key?(:controller)
|
|
25
|
+
assert response[:body][:data][:extra_data].has_key?(:data_item1)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
test "should call pre/post_callback if specified" do
|
|
29
|
+
HTTParty.stubs(:send).returns(fake_response)
|
|
30
|
+
webhook = ExceptionNotifier::WebhookNotifier.new({:url => 'http://localhost:8000'})
|
|
31
|
+
webhook.call(fake_exception)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def fake_response
|
|
37
|
+
{
|
|
38
|
+
:status => 200,
|
|
39
|
+
:body => {
|
|
40
|
+
:exception => {
|
|
41
|
+
:error_class => 'ZeroDivisionError',
|
|
42
|
+
:message => 'divided by 0',
|
|
43
|
+
:backtrace => '/exception_notification/test/webhook_notifier_test.rb:48:in `/'
|
|
44
|
+
},
|
|
45
|
+
:data => {
|
|
46
|
+
:extra_data => {:data_item1 => "datavalue1", :data_item2 => "datavalue2"}
|
|
47
|
+
},
|
|
48
|
+
:request => {
|
|
49
|
+
:cookies => {:cookie_item1 => 'cookieitemvalue1', :cookie_item2 => 'cookieitemvalue2'},
|
|
50
|
+
:url => 'http://example.com/example',
|
|
51
|
+
:ip_address => '192.168.1.1',
|
|
52
|
+
:environment => {:env_item1 => "envitem1", :env_item2 => "envitem2"},
|
|
53
|
+
:controller => '#<ControllerName:0x007f9642a04d00>',
|
|
54
|
+
:session => {:session_item1 => "sessionitem1", :session_item2 => "sessionitem2"},
|
|
55
|
+
:parameters => {:action =>"index", :controller =>"projects"}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def fake_exception
|
|
62
|
+
exception = begin
|
|
63
|
+
5/0
|
|
64
|
+
rescue Exception => e
|
|
65
|
+
e
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class ExceptionNotifierTest < ActiveSupport::TestCase
|
|
4
|
+
test "should have default ignored exceptions" do
|
|
5
|
+
assert_equal ExceptionNotifier.ignored_exceptions, ['ActiveRecord::RecordNotFound', 'AbstractController::ActionNotFound', 'ActionController::RoutingError', 'ActionController::UnknownFormat']
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
test "should have email notifier registered" do
|
|
9
|
+
assert_equal ExceptionNotifier.notifiers, [:email]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
test "should have a valid email notifier" do
|
|
13
|
+
@email_notifier = ExceptionNotifier.registered_exception_notifier(:email)
|
|
14
|
+
refute_nil @email_notifier
|
|
15
|
+
assert_equal @email_notifier.class, ExceptionNotifier::EmailNotifier
|
|
16
|
+
assert_respond_to @email_notifier, :call
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
test "should allow register/unregister another notifier" do
|
|
20
|
+
called = false
|
|
21
|
+
proc_notifier = lambda { |exception, options| called = true }
|
|
22
|
+
ExceptionNotifier.register_exception_notifier(:proc, proc_notifier)
|
|
23
|
+
|
|
24
|
+
assert_equal ExceptionNotifier.notifiers.sort, [:email, :proc]
|
|
25
|
+
|
|
26
|
+
exception = StandardError.new
|
|
27
|
+
|
|
28
|
+
ExceptionNotifier.notify_exception(exception)
|
|
29
|
+
assert called
|
|
30
|
+
|
|
31
|
+
ExceptionNotifier.unregister_exception_notifier(:proc)
|
|
32
|
+
assert_equal ExceptionNotifier.notifiers, [:email]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
test "should allow select notifiers to send error to" do
|
|
36
|
+
notifier1_calls = 0
|
|
37
|
+
notifier1 = lambda { |exception, options| notifier1_calls += 1 }
|
|
38
|
+
ExceptionNotifier.register_exception_notifier(:notifier1, notifier1)
|
|
39
|
+
|
|
40
|
+
notifier2_calls = 0
|
|
41
|
+
notifier2 = lambda { |exception, options| notifier2_calls += 1 }
|
|
42
|
+
ExceptionNotifier.register_exception_notifier(:notifier2, notifier2)
|
|
43
|
+
|
|
44
|
+
assert_equal ExceptionNotifier.notifiers.sort, [:email, :notifier1, :notifier2]
|
|
45
|
+
|
|
46
|
+
exception = StandardError.new
|
|
47
|
+
ExceptionNotifier.notify_exception(exception)
|
|
48
|
+
assert_equal notifier1_calls, 1
|
|
49
|
+
assert_equal notifier2_calls, 1
|
|
50
|
+
|
|
51
|
+
ExceptionNotifier.notify_exception(exception, {:notifiers => :notifier1})
|
|
52
|
+
assert_equal notifier1_calls, 2
|
|
53
|
+
assert_equal notifier2_calls, 1
|
|
54
|
+
|
|
55
|
+
ExceptionNotifier.notify_exception(exception, {:notifiers => :notifier2})
|
|
56
|
+
assert_equal notifier1_calls, 2
|
|
57
|
+
assert_equal notifier2_calls, 2
|
|
58
|
+
|
|
59
|
+
ExceptionNotifier.unregister_exception_notifier(:notifier1)
|
|
60
|
+
ExceptionNotifier.unregister_exception_notifier(:notifier2)
|
|
61
|
+
assert_equal ExceptionNotifier.notifiers, [:email]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
test "should ignore exception if satisfies conditional ignore" do
|
|
65
|
+
env = "production"
|
|
66
|
+
ExceptionNotifier.ignore_if do |exception, options|
|
|
67
|
+
env != "production"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
notifier_calls = 0
|
|
71
|
+
test_notifier = lambda { |exception, options| notifier_calls += 1 }
|
|
72
|
+
ExceptionNotifier.register_exception_notifier(:test, test_notifier)
|
|
73
|
+
|
|
74
|
+
exception = StandardError.new
|
|
75
|
+
|
|
76
|
+
ExceptionNotifier.notify_exception(exception, {:notifiers => :test})
|
|
77
|
+
assert_equal notifier_calls, 1
|
|
78
|
+
|
|
79
|
+
env = "development"
|
|
80
|
+
ExceptionNotifier.notify_exception(exception, {:notifiers => :test})
|
|
81
|
+
assert_equal notifier_calls, 1
|
|
82
|
+
|
|
83
|
+
ExceptionNotifier.clear_ignore_conditions!
|
|
84
|
+
ExceptionNotifier.unregister_exception_notifier(:test)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
test "should not send notification if one of ignored exceptions" do
|
|
88
|
+
notifier_calls = 0
|
|
89
|
+
test_notifier = lambda { |exception, options| notifier_calls += 1 }
|
|
90
|
+
ExceptionNotifier.register_exception_notifier(:test, test_notifier)
|
|
91
|
+
|
|
92
|
+
exception = StandardError.new
|
|
93
|
+
|
|
94
|
+
ExceptionNotifier.notify_exception(exception, {:notifiers => :test})
|
|
95
|
+
assert_equal notifier_calls, 1
|
|
96
|
+
|
|
97
|
+
ExceptionNotifier.notify_exception(exception, {:notifiers => :test, :ignore_exceptions => 'StandardError' })
|
|
98
|
+
assert_equal notifier_calls, 1
|
|
99
|
+
|
|
100
|
+
ExceptionNotifier.unregister_exception_notifier(:test)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
end
|