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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<% filtered_env = @request.filtered_env -%>
|
|
2
2
|
<% max = filtered_env.keys.map(&:to_s).max { |a, b| a.length <=> b.length } -%>
|
|
3
3
|
<% filtered_env.keys.map(&:to_s).sort.each do |key| -%>
|
|
4
|
-
* <%= raw safe_encode("%-*s: %s" % [max.length, key, inspect_object(filtered_env[key])]) %>
|
|
4
|
+
* <%= raw safe_encode("%-*s: %s" % [max.length, key, inspect_object(filtered_env[key])]).strip %>
|
|
5
5
|
<% end -%>
|
data/lib/exception_notifier/views/exception_notifier/background_exception_notification.text.erb
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
<%= @exception.message %>
|
|
4
4
|
<%= @backtrace.first %>
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
<% sections = @sections.map do |section|
|
|
7
|
+
summary = render(section).strip
|
|
8
|
+
unless summary.blank?
|
|
9
|
+
title = render("title", :title => section).strip
|
|
10
|
+
"#{title}\n\n#{summary.gsub(/^/, " ")}\n\n"
|
|
11
|
+
end
|
|
12
|
+
end.join
|
|
13
|
+
%>
|
|
14
|
+
<%= raw sections %>
|
|
@@ -11,14 +11,12 @@
|
|
|
11
11
|
begin
|
|
12
12
|
summary = render(section).strip
|
|
13
13
|
unless summary.blank?
|
|
14
|
-
title = render("title", :
|
|
14
|
+
title = render("title", title: section).strip
|
|
15
15
|
[title, summary]
|
|
16
16
|
end
|
|
17
|
-
|
|
18
17
|
rescue Exception => e
|
|
19
|
-
title = render("title", :
|
|
18
|
+
title = render("title", title: section).strip
|
|
20
19
|
summary = ["ERROR: Failed to generate exception summary:", [e.class.to_s, e.message].join(": "), e.backtrace && e.backtrace.join("\n")].compact.join("\n\n")
|
|
21
|
-
|
|
22
20
|
[title, summary]
|
|
23
21
|
end
|
|
24
22
|
end
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
begin
|
|
9
9
|
summary = render(section).strip
|
|
10
10
|
unless summary.blank?
|
|
11
|
-
title = render("title", :
|
|
11
|
+
title = render("title", title: section).strip
|
|
12
12
|
"#{title}\n\n#{summary.gsub(/^/, " ")}\n\n"
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
rescue Exception => e
|
|
16
|
-
title = render("title", :
|
|
16
|
+
title = render("title", title: section).strip
|
|
17
17
|
summary = ["ERROR: Failed to generate exception summary:", [e.class.to_s, e.message].join(": "), e.backtrace && e.backtrace.join("\n")].compact.join("\n\n")
|
|
18
18
|
|
|
19
19
|
[title, summary.gsub(/^/, " "), nil].join("\n\n")
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'action_dispatch'
|
|
2
4
|
require 'active_support/core_ext/time'
|
|
3
5
|
|
|
4
6
|
module ExceptionNotifier
|
|
5
7
|
class WebhookNotifier < BaseNotifier
|
|
6
|
-
|
|
7
8
|
def initialize(options)
|
|
8
9
|
super
|
|
9
10
|
@default_options = options
|
|
10
11
|
end
|
|
11
12
|
|
|
12
|
-
def call(exception, options={})
|
|
13
|
+
def call(exception, options = {})
|
|
13
14
|
env = options[:env]
|
|
14
15
|
|
|
15
16
|
options = options.reverse_merge(@default_options)
|
|
@@ -18,23 +19,25 @@ module ExceptionNotifier
|
|
|
18
19
|
|
|
19
20
|
options[:body] ||= {}
|
|
20
21
|
options[:body][:server] = Socket.gethostname
|
|
21
|
-
options[:body][:process] =
|
|
22
|
-
if defined?(Rails) && Rails.respond_to?(:root)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
options[:body][:process] = $PROCESS_ID
|
|
23
|
+
options[:body][:rails_root] = Rails.root if defined?(Rails) && Rails.respond_to?(:root)
|
|
24
|
+
options[:body][:exception] = {
|
|
25
|
+
error_class: exception.class.to_s,
|
|
26
|
+
message: exception.message.inspect,
|
|
27
|
+
backtrace: exception.backtrace
|
|
28
|
+
}
|
|
28
29
|
options[:body][:data] = (env && env['exception_notifier.exception_data'] || {}).merge(options[:data] || {})
|
|
29
30
|
|
|
30
31
|
unless env.nil?
|
|
31
32
|
request = ActionDispatch::Request.new(env)
|
|
32
33
|
|
|
33
|
-
request_items = {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
request_items = {
|
|
35
|
+
url: request.original_url,
|
|
36
|
+
http_method: request.method,
|
|
37
|
+
ip_address: request.remote_ip,
|
|
38
|
+
parameters: request.filtered_parameters,
|
|
39
|
+
timestamp: Time.current
|
|
40
|
+
}
|
|
38
41
|
|
|
39
42
|
options[:body][:request] = request_items
|
|
40
43
|
options[:body][:session] = request.session
|
|
@@ -1,14 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ExceptionNotification
|
|
2
4
|
module Generators
|
|
3
5
|
class InstallGenerator < Rails::Generators::Base
|
|
4
|
-
desc
|
|
6
|
+
desc 'Creates a ExceptionNotification initializer.'
|
|
5
7
|
|
|
6
|
-
source_root File.expand_path('
|
|
7
|
-
class_option :resque,
|
|
8
|
-
|
|
8
|
+
source_root File.expand_path('templates', __dir__)
|
|
9
|
+
class_option :resque,
|
|
10
|
+
type: :boolean,
|
|
11
|
+
desc: 'Add support for sending notifications when errors occur in Resque jobs.'
|
|
12
|
+
class_option :sidekiq,
|
|
13
|
+
type: :boolean,
|
|
14
|
+
desc: 'Add support for sending notifications when errors occur in Sidekiq jobs.'
|
|
9
15
|
|
|
10
16
|
def copy_initializer
|
|
11
|
-
template 'exception_notification.rb', 'config/initializers/exception_notification.rb'
|
|
17
|
+
template 'exception_notification.rb.erb', 'config/initializers/exception_notification.rb'
|
|
12
18
|
end
|
|
13
19
|
end
|
|
14
20
|
end
|
|
@@ -22,32 +22,34 @@ ExceptionNotification.configure do |config|
|
|
|
22
22
|
# not Rails.env.production?
|
|
23
23
|
# end
|
|
24
24
|
|
|
25
|
+
# Ignore exceptions generated by crawlers
|
|
26
|
+
# config.ignore_crawlers %w{Googlebot bingbot}
|
|
27
|
+
|
|
25
28
|
# Notifiers =================================================================
|
|
26
29
|
|
|
27
30
|
# Email notifier sends notifications by email.
|
|
28
31
|
config.add_notifier :email, {
|
|
29
|
-
:
|
|
30
|
-
:
|
|
31
|
-
:
|
|
32
|
+
email_prefix: '[ERROR] ',
|
|
33
|
+
sender_address: %{"Notifier" <notifier@example.com>},
|
|
34
|
+
exception_recipients: %w{exceptions@example.com}
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
# Campfire notifier sends notifications to your Campfire room. Requires 'tinder' gem.
|
|
35
38
|
# config.add_notifier :campfire, {
|
|
36
|
-
# :
|
|
37
|
-
# :
|
|
38
|
-
# :
|
|
39
|
+
# subdomain: 'my_subdomain',
|
|
40
|
+
# token: 'my_token',
|
|
41
|
+
# room_name: 'my_room'
|
|
39
42
|
# }
|
|
40
43
|
|
|
41
44
|
# HipChat notifier sends notifications to your HipChat room. Requires 'hipchat' gem.
|
|
42
45
|
# config.add_notifier :hipchat, {
|
|
43
|
-
# :
|
|
44
|
-
# :
|
|
46
|
+
# api_token: 'my_token',
|
|
47
|
+
# room_name: 'my_room'
|
|
45
48
|
# }
|
|
46
49
|
|
|
47
50
|
# Webhook notifier sends notifications over HTTP protocol. Requires 'httparty' gem.
|
|
48
51
|
# config.add_notifier :webhook, {
|
|
49
|
-
# :
|
|
50
|
-
# :
|
|
52
|
+
# url: 'http://example.com:5555/hubot/path',
|
|
53
|
+
# http_method: :post
|
|
51
54
|
# }
|
|
52
|
-
|
|
53
55
|
end
|
|
@@ -1,20 +1,106 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'test_helper'
|
|
2
4
|
|
|
3
5
|
class RackTest < ActiveSupport::TestCase
|
|
4
|
-
|
|
5
6
|
setup do
|
|
6
7
|
@pass_app = Object.new
|
|
7
8
|
@pass_app.stubs(:call).returns([nil, { 'X-Cascade' => 'pass' }, nil])
|
|
9
|
+
|
|
10
|
+
@normal_app = Object.new
|
|
11
|
+
@normal_app.stubs(:call).returns([nil, {}, nil])
|
|
8
12
|
end
|
|
9
13
|
|
|
10
|
-
|
|
14
|
+
teardown do
|
|
15
|
+
ExceptionNotifier.reset_notifiers!
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
test 'should ignore "X-Cascade" header by default' do
|
|
11
19
|
ExceptionNotifier.expects(:notify_exception).never
|
|
12
20
|
ExceptionNotification::Rack.new(@pass_app).call({})
|
|
13
21
|
end
|
|
14
22
|
|
|
15
|
-
test
|
|
23
|
+
test 'should notify on "X-Cascade" = "pass" if ignore_cascade_pass option is false' do
|
|
16
24
|
ExceptionNotifier.expects(:notify_exception).once
|
|
17
|
-
ExceptionNotification::Rack.new(@pass_app, :
|
|
25
|
+
ExceptionNotification::Rack.new(@pass_app, ignore_cascade_pass: false).call({})
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
test 'should assign error_grouping if error_grouping is specified' do
|
|
29
|
+
refute ExceptionNotifier.error_grouping
|
|
30
|
+
ExceptionNotification::Rack.new(@normal_app, error_grouping: true).call({})
|
|
31
|
+
assert ExceptionNotifier.error_grouping
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
test 'should assign notification_trigger if notification_trigger is specified' do
|
|
35
|
+
assert_nil ExceptionNotifier.notification_trigger
|
|
36
|
+
ExceptionNotification::Rack.new(@normal_app, notification_trigger: ->(_i) { true }).call({})
|
|
37
|
+
assert_respond_to ExceptionNotifier.notification_trigger, :call
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if defined?(Rails) && Rails.respond_to?(:cache)
|
|
41
|
+
test 'should set default cache to Rails cache' do
|
|
42
|
+
ExceptionNotification::Rack.new(@normal_app, error_grouping: true).call({})
|
|
43
|
+
assert_equal Rails.cache, ExceptionNotifier.error_grouping_cache
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
test 'should ignore exceptions with Usar Agent in ignore_crawlers' do
|
|
48
|
+
exception_app = Object.new
|
|
49
|
+
exception_app.stubs(:call).raises(RuntimeError)
|
|
50
|
+
|
|
51
|
+
env = { 'HTTP_USER_AGENT' => 'Mozilla/5.0 (compatible; Crawlerbot/2.1;)' }
|
|
52
|
+
|
|
53
|
+
begin
|
|
54
|
+
ExceptionNotification::Rack.new(exception_app, ignore_crawlers: %w[Crawlerbot]).call(env)
|
|
55
|
+
|
|
56
|
+
flunk
|
|
57
|
+
rescue StandardError
|
|
58
|
+
refute env['exception_notifier.delivered']
|
|
59
|
+
end
|
|
18
60
|
end
|
|
19
61
|
|
|
62
|
+
test 'should ignore exceptions if ignore_if condition is met' do
|
|
63
|
+
exception_app = Object.new
|
|
64
|
+
exception_app.stubs(:call).raises(RuntimeError)
|
|
65
|
+
|
|
66
|
+
env = {}
|
|
67
|
+
|
|
68
|
+
begin
|
|
69
|
+
ExceptionNotification::Rack.new(
|
|
70
|
+
exception_app,
|
|
71
|
+
ignore_if: ->(_env, exception) { exception.is_a? RuntimeError }
|
|
72
|
+
).call(env)
|
|
73
|
+
|
|
74
|
+
flunk
|
|
75
|
+
rescue StandardError
|
|
76
|
+
refute env['exception_notifier.delivered']
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
test 'should ignore exceptions with notifiers that satisfies ignore_notifier_if condition' do
|
|
81
|
+
exception_app = Object.new
|
|
82
|
+
exception_app.stubs(:call).raises(RuntimeError)
|
|
83
|
+
|
|
84
|
+
notifier1_called = notifier2_called = false
|
|
85
|
+
notifier1 = ->(_exception, _options) { notifier1_called = true }
|
|
86
|
+
notifier2 = ->(_exception, _options) { notifier2_called = true }
|
|
87
|
+
|
|
88
|
+
env = {}
|
|
89
|
+
|
|
90
|
+
begin
|
|
91
|
+
ExceptionNotification::Rack.new(
|
|
92
|
+
exception_app,
|
|
93
|
+
ignore_notifier_if: {
|
|
94
|
+
notifier1: ->(_env, exception) { exception.is_a? RuntimeError }
|
|
95
|
+
},
|
|
96
|
+
notifier1: notifier1,
|
|
97
|
+
notifier2: notifier2
|
|
98
|
+
).call(env)
|
|
99
|
+
|
|
100
|
+
flunk
|
|
101
|
+
rescue StandardError
|
|
102
|
+
refute notifier1_called
|
|
103
|
+
assert notifier2_called
|
|
104
|
+
end
|
|
105
|
+
end
|
|
20
106
|
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
|
|
5
|
+
require 'exception_notification/resque'
|
|
6
|
+
require 'resque'
|
|
7
|
+
require 'mock_redis'
|
|
8
|
+
require 'resque/failure/multiple'
|
|
9
|
+
require 'resque/failure/redis'
|
|
10
|
+
|
|
11
|
+
class ResqueTest < ActiveSupport::TestCase
|
|
12
|
+
setup do
|
|
13
|
+
# Resque.redis=() only supports a String or Redis instance in Resque 1.8
|
|
14
|
+
Resque.instance_variable_set(:@redis, MockRedis.new)
|
|
15
|
+
|
|
16
|
+
Resque::Failure::Multiple.classes = [Resque::Failure::Redis, ExceptionNotification::Resque]
|
|
17
|
+
Resque::Failure.backend = Resque::Failure::Multiple
|
|
18
|
+
|
|
19
|
+
@worker = Resque::Worker.new(:jobs)
|
|
20
|
+
# Forking causes issues with Mocha's `.expects`
|
|
21
|
+
@worker.cant_fork = true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
test 'count returns the number of failures' do
|
|
25
|
+
Resque::Job.create(:jobs, BadJob)
|
|
26
|
+
@worker.work(0)
|
|
27
|
+
assert_equal 1, ExceptionNotification::Resque.count
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
test 'notifies exception when job fails' do
|
|
31
|
+
ExceptionNotifier.expects(:notify_exception).with do |ex, opts|
|
|
32
|
+
ex.is_a?(RuntimeError) &&
|
|
33
|
+
ex.message == 'Bad job!' &&
|
|
34
|
+
opts[:data][:resque][:error_class] == 'RuntimeError' &&
|
|
35
|
+
opts[:data][:resque][:error_message] == 'Bad job!' &&
|
|
36
|
+
opts[:data][:resque][:failed_at].present? &&
|
|
37
|
+
opts[:data][:resque][:payload] == {
|
|
38
|
+
'class' => 'ResqueTest::BadJob',
|
|
39
|
+
'args' => []
|
|
40
|
+
} &&
|
|
41
|
+
opts[:data][:resque][:queue] == :jobs &&
|
|
42
|
+
opts[:data][:resque][:worker].present?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
Resque::Job.create(:jobs, BadJob)
|
|
46
|
+
@worker.work(0)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
class BadJob
|
|
50
|
+
def self.perform
|
|
51
|
+
raise 'Bad job!'
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'test_helper'
|
|
2
4
|
|
|
3
5
|
# silence_warnings trick around require can be removed once
|
|
@@ -8,43 +10,42 @@ silence_warnings do
|
|
|
8
10
|
end
|
|
9
11
|
|
|
10
12
|
class CampfireNotifierTest < ActiveSupport::TestCase
|
|
11
|
-
|
|
12
|
-
test "should send campfire notification if properly configured" do
|
|
13
|
+
test 'should send campfire notification if properly configured' do
|
|
13
14
|
ExceptionNotifier::CampfireNotifier.stubs(:new).returns(Object.new)
|
|
14
|
-
campfire = ExceptionNotifier::CampfireNotifier.new(
|
|
15
|
+
campfire = ExceptionNotifier::CampfireNotifier.new(subdomain: 'test', token: 'test_token', room_name: 'test_room')
|
|
15
16
|
campfire.stubs(:call).returns(fake_notification)
|
|
16
17
|
notif = campfire.call(fake_exception)
|
|
17
18
|
|
|
18
19
|
assert !notif[:message].empty?
|
|
19
20
|
assert_equal notif[:message][:type], 'PasteMessage'
|
|
20
|
-
assert_includes notif[:message][:body],
|
|
21
|
-
assert_includes notif[:message][:body],
|
|
22
|
-
assert_includes notif[:message][:body],
|
|
21
|
+
assert_includes notif[:message][:body], 'A new exception occurred:'
|
|
22
|
+
assert_includes notif[:message][:body], 'divided by 0'
|
|
23
|
+
assert_includes notif[:message][:body], '/exception_notification/test/campfire_test.rb:45'
|
|
23
24
|
end
|
|
24
25
|
|
|
25
|
-
test
|
|
26
|
+
test 'should send campfire notification without backtrace info if properly configured' do
|
|
26
27
|
ExceptionNotifier::CampfireNotifier.stubs(:new).returns(Object.new)
|
|
27
|
-
campfire = ExceptionNotifier::CampfireNotifier.new(
|
|
28
|
+
campfire = ExceptionNotifier::CampfireNotifier.new(subdomain: 'test', token: 'test_token', room_name: 'test_room')
|
|
28
29
|
campfire.stubs(:call).returns(fake_notification_without_backtrace)
|
|
29
30
|
notif = campfire.call(fake_exception_without_backtrace)
|
|
30
31
|
|
|
31
32
|
assert !notif[:message].empty?
|
|
32
33
|
assert_equal notif[:message][:type], 'PasteMessage'
|
|
33
|
-
assert_includes notif[:message][:body],
|
|
34
|
-
assert_includes notif[:message][:body],
|
|
34
|
+
assert_includes notif[:message][:body], 'A new exception occurred:'
|
|
35
|
+
assert_includes notif[:message][:body], 'my custom error'
|
|
35
36
|
end
|
|
36
37
|
|
|
37
|
-
test
|
|
38
|
-
wrong_params = {:
|
|
39
|
-
Tinder::Campfire.stubs(:new).with('test',
|
|
38
|
+
test 'should not send campfire notification if badly configured' do
|
|
39
|
+
wrong_params = { subdomain: 'test', token: 'bad_token', room_name: 'test_room' }
|
|
40
|
+
Tinder::Campfire.stubs(:new).with('test', token: 'bad_token').returns(nil)
|
|
40
41
|
campfire = ExceptionNotifier::CampfireNotifier.new(wrong_params)
|
|
41
42
|
|
|
42
43
|
assert_nil campfire.room
|
|
43
44
|
assert_nil campfire.call(fake_exception)
|
|
44
45
|
end
|
|
45
46
|
|
|
46
|
-
test
|
|
47
|
-
wrong_params
|
|
47
|
+
test 'should not send campfire notification if config attr missing' do
|
|
48
|
+
wrong_params = { subdomain: 'test', room_name: 'test_room' }
|
|
48
49
|
Tinder::Campfire.stubs(:new).with('test', {}).returns(nil)
|
|
49
50
|
campfire = ExceptionNotifier::CampfireNotifier.new(wrong_params)
|
|
50
51
|
|
|
@@ -52,21 +53,34 @@ class CampfireNotifierTest < ActiveSupport::TestCase
|
|
|
52
53
|
assert_nil campfire.call(fake_exception)
|
|
53
54
|
end
|
|
54
55
|
|
|
55
|
-
test
|
|
56
|
-
|
|
56
|
+
test 'should send the new exception message if no :accumulated_errors_count option' do
|
|
57
|
+
campfire = ExceptionNotifier::CampfireNotifier.new({})
|
|
58
|
+
campfire.stubs(:active?).returns(true)
|
|
59
|
+
campfire.expects(:send_notice).with { |_, _, message| message.start_with?('A new exception occurred') }.once
|
|
60
|
+
campfire.call(fake_exception)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
test 'shoud send the exception message if :accumulated_errors_count option greater than 1' do
|
|
64
|
+
campfire = ExceptionNotifier::CampfireNotifier.new({})
|
|
65
|
+
campfire.stubs(:active?).returns(true)
|
|
66
|
+
campfire.expects(:send_notice).with { |_, _, message| message.start_with?('The exception occurred 3 times:') }.once
|
|
67
|
+
campfire.call(fake_exception, accumulated_errors_count: 3)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
test 'should call pre/post_callback if specified' do
|
|
71
|
+
pre_callback_called = 0
|
|
72
|
+
post_callback_called = 0
|
|
57
73
|
Tinder::Campfire.stubs(:new).returns(Object.new)
|
|
58
74
|
|
|
59
75
|
campfire = ExceptionNotifier::CampfireNotifier.new(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
post_callback_called += 1
|
|
69
|
-
}
|
|
76
|
+
subdomain: 'test',
|
|
77
|
+
token: 'test_token',
|
|
78
|
+
room_name: 'test_room',
|
|
79
|
+
pre_callback: proc { |_opts, _notifier, _backtrace, _message, _message_opts|
|
|
80
|
+
pre_callback_called += 1
|
|
81
|
+
},
|
|
82
|
+
post_callback: proc { |_opts, _notifier, _backtrace, _message, _message_opts|
|
|
83
|
+
post_callback_called += 1
|
|
70
84
|
}
|
|
71
85
|
)
|
|
72
86
|
campfire.room = Object.new
|
|
@@ -79,24 +93,31 @@ class CampfireNotifierTest < ActiveSupport::TestCase
|
|
|
79
93
|
private
|
|
80
94
|
|
|
81
95
|
def fake_notification
|
|
82
|
-
{
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
{
|
|
97
|
+
message: {
|
|
98
|
+
type: 'PasteMessage',
|
|
99
|
+
body: fake_notification_body
|
|
100
|
+
}
|
|
85
101
|
}
|
|
86
102
|
end
|
|
87
103
|
|
|
104
|
+
def fake_notification_body
|
|
105
|
+
"A new exception occurred: 'divided by 0' on " \
|
|
106
|
+
"/Users/sebastian/exception_notification/test/campfire_test.rb:45:in `/'"
|
|
107
|
+
end
|
|
108
|
+
|
|
88
109
|
def fake_exception
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
e
|
|
93
|
-
end
|
|
110
|
+
5 / 0
|
|
111
|
+
rescue StandardError => e
|
|
112
|
+
e
|
|
94
113
|
end
|
|
95
114
|
|
|
96
115
|
def fake_notification_without_backtrace
|
|
97
|
-
{
|
|
98
|
-
|
|
99
|
-
|
|
116
|
+
{
|
|
117
|
+
message: {
|
|
118
|
+
type: 'PasteMessage',
|
|
119
|
+
body: "A new exception occurred: 'my custom error'"
|
|
120
|
+
}
|
|
100
121
|
}
|
|
101
122
|
end
|
|
102
123
|
|