exception_notification 4.2.0 → 4.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +5 -5
  2. data/Appraisals +4 -3
  3. data/CHANGELOG.rdoc +57 -1
  4. data/CONTRIBUTING.md +21 -2
  5. data/Gemfile +3 -1
  6. data/README.md +106 -789
  7. data/Rakefile +4 -2
  8. data/docs/notifiers/campfire.md +50 -0
  9. data/docs/notifiers/custom.md +42 -0
  10. data/docs/notifiers/datadog.md +51 -0
  11. data/docs/notifiers/email.md +195 -0
  12. data/docs/notifiers/google_chat.md +31 -0
  13. data/docs/notifiers/hipchat.md +66 -0
  14. data/docs/notifiers/irc.md +97 -0
  15. data/docs/notifiers/mattermost.md +115 -0
  16. data/docs/notifiers/slack.md +161 -0
  17. data/docs/notifiers/sns.md +37 -0
  18. data/docs/notifiers/teams.md +54 -0
  19. data/docs/notifiers/webhook.md +60 -0
  20. data/examples/sample_app.rb +56 -0
  21. data/examples/sinatra/Gemfile +8 -6
  22. data/examples/sinatra/config.ru +3 -1
  23. data/examples/sinatra/sinatra_app.rb +19 -11
  24. data/exception_notification.gemspec +30 -23
  25. data/gemfiles/rails4_0.gemfile +1 -2
  26. data/gemfiles/rails4_1.gemfile +1 -2
  27. data/gemfiles/rails4_2.gemfile +1 -2
  28. data/gemfiles/rails5_0.gemfile +1 -2
  29. data/gemfiles/rails5_1.gemfile +7 -0
  30. data/gemfiles/rails5_2.gemfile +7 -0
  31. data/gemfiles/rails6_0.gemfile +7 -0
  32. data/lib/exception_notification.rb +3 -0
  33. data/lib/exception_notification/rack.rb +34 -27
  34. data/lib/exception_notification/rails.rb +3 -0
  35. data/lib/exception_notification/resque.rb +10 -10
  36. data/lib/exception_notification/sidekiq.rb +10 -12
  37. data/lib/exception_notification/version.rb +5 -0
  38. data/lib/exception_notifier.rb +79 -11
  39. data/lib/exception_notifier/base_notifier.rb +10 -5
  40. data/lib/exception_notifier/campfire_notifier.rb +14 -9
  41. data/lib/exception_notifier/datadog_notifier.rb +156 -0
  42. data/lib/exception_notifier/email_notifier.rb +78 -87
  43. data/lib/exception_notifier/google_chat_notifier.rb +44 -0
  44. data/lib/exception_notifier/hipchat_notifier.rb +16 -10
  45. data/lib/exception_notifier/irc_notifier.rb +38 -31
  46. data/lib/exception_notifier/mattermost_notifier.rb +54 -131
  47. data/lib/exception_notifier/modules/backtrace_cleaner.rb +2 -2
  48. data/lib/exception_notifier/modules/error_grouping.rb +87 -0
  49. data/lib/exception_notifier/modules/formatter.rb +121 -0
  50. data/lib/exception_notifier/notifier.rb +9 -6
  51. data/lib/exception_notifier/slack_notifier.rb +75 -32
  52. data/lib/exception_notifier/sns_notifier.rb +86 -0
  53. data/lib/exception_notifier/teams_notifier.rb +200 -0
  54. data/lib/exception_notifier/views/exception_notifier/_backtrace.html.erb +1 -1
  55. data/lib/exception_notifier/views/exception_notifier/_environment.text.erb +1 -1
  56. data/lib/exception_notifier/views/exception_notifier/_request.text.erb +1 -1
  57. data/lib/exception_notifier/views/exception_notifier/background_exception_notification.text.erb +9 -9
  58. data/lib/exception_notifier/views/exception_notifier/exception_notification.html.erb +2 -4
  59. data/lib/exception_notifier/views/exception_notifier/exception_notification.text.erb +2 -2
  60. data/lib/exception_notifier/webhook_notifier.rb +19 -16
  61. data/lib/generators/exception_notification/install_generator.rb +11 -5
  62. data/lib/generators/exception_notification/templates/{exception_notification.rb → exception_notification.rb.erb} +14 -12
  63. data/test/exception_notification/rack_test.rb +90 -4
  64. data/test/exception_notification/resque_test.rb +54 -0
  65. data/test/exception_notifier/campfire_notifier_test.rb +66 -39
  66. data/test/exception_notifier/datadog_notifier_test.rb +153 -0
  67. data/test/exception_notifier/email_notifier_test.rb +301 -145
  68. data/test/exception_notifier/google_chat_notifier_test.rb +185 -0
  69. data/test/exception_notifier/hipchat_notifier_test.rb +112 -65
  70. data/test/exception_notifier/irc_notifier_test.rb +48 -30
  71. data/test/exception_notifier/mattermost_notifier_test.rb +218 -55
  72. data/test/exception_notifier/modules/error_grouping_test.rb +167 -0
  73. data/test/exception_notifier/modules/formatter_test.rb +152 -0
  74. data/test/exception_notifier/sidekiq_test.rb +9 -6
  75. data/test/exception_notifier/slack_notifier_test.rb +109 -59
  76. data/test/exception_notifier/sns_notifier_test.rb +123 -0
  77. data/test/exception_notifier/teams_notifier_test.rb +92 -0
  78. data/test/exception_notifier/webhook_notifier_test.rb +68 -38
  79. data/test/exception_notifier_test.rb +220 -37
  80. data/test/support/exception_notifier_helper.rb +14 -0
  81. data/test/{dummy/app → support}/views/exception_notifier/_new_bkg_section.html.erb +0 -0
  82. data/test/{dummy/app → support}/views/exception_notifier/_new_bkg_section.text.erb +0 -0
  83. data/test/{dummy/app → support}/views/exception_notifier/_new_section.html.erb +0 -0
  84. data/test/{dummy/app → support}/views/exception_notifier/_new_section.text.erb +0 -0
  85. data/test/test_helper.rb +14 -13
  86. metadata +154 -162
  87. data/test/dummy/.gitignore +0 -4
  88. data/test/dummy/Rakefile +0 -7
  89. data/test/dummy/app/controllers/application_controller.rb +0 -3
  90. data/test/dummy/app/controllers/posts_controller.rb +0 -30
  91. data/test/dummy/app/helpers/application_helper.rb +0 -2
  92. data/test/dummy/app/helpers/posts_helper.rb +0 -2
  93. data/test/dummy/app/models/post.rb +0 -2
  94. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  95. data/test/dummy/app/views/posts/_form.html.erb +0 -0
  96. data/test/dummy/app/views/posts/new.html.erb +0 -0
  97. data/test/dummy/app/views/posts/show.html.erb +0 -0
  98. data/test/dummy/config.ru +0 -4
  99. data/test/dummy/config/application.rb +0 -42
  100. data/test/dummy/config/boot.rb +0 -6
  101. data/test/dummy/config/database.yml +0 -22
  102. data/test/dummy/config/environment.rb +0 -17
  103. data/test/dummy/config/environments/development.rb +0 -25
  104. data/test/dummy/config/environments/production.rb +0 -50
  105. data/test/dummy/config/environments/test.rb +0 -38
  106. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  107. data/test/dummy/config/initializers/inflections.rb +0 -10
  108. data/test/dummy/config/initializers/mime_types.rb +0 -5
  109. data/test/dummy/config/initializers/secret_token.rb +0 -8
  110. data/test/dummy/config/initializers/session_store.rb +0 -8
  111. data/test/dummy/config/locales/en.yml +0 -5
  112. data/test/dummy/config/routes.rb +0 -3
  113. data/test/dummy/db/migrate/20110729022608_create_posts.rb +0 -15
  114. data/test/dummy/db/schema.rb +0 -24
  115. data/test/dummy/db/seeds.rb +0 -7
  116. data/test/dummy/lib/tasks/.gitkeep +0 -0
  117. data/test/dummy/public/404.html +0 -26
  118. data/test/dummy/public/422.html +0 -26
  119. data/test/dummy/public/500.html +0 -26
  120. data/test/dummy/public/favicon.ico +0 -0
  121. data/test/dummy/public/images/rails.png +0 -0
  122. data/test/dummy/public/index.html +0 -239
  123. data/test/dummy/public/javascripts/application.js +0 -2
  124. data/test/dummy/public/javascripts/controls.js +0 -965
  125. data/test/dummy/public/javascripts/dragdrop.js +0 -974
  126. data/test/dummy/public/javascripts/effects.js +0 -1123
  127. data/test/dummy/public/javascripts/prototype.js +0 -6001
  128. data/test/dummy/public/javascripts/rails.js +0 -191
  129. data/test/dummy/public/robots.txt +0 -5
  130. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  131. data/test/dummy/public/stylesheets/scaffold.css +0 -56
  132. data/test/dummy/script/rails +0 -6
  133. data/test/dummy/test/functional/posts_controller_test.rb +0 -218
  134. data/test/dummy/test/test_helper.rb +0 -7
@@ -1,3 +1,3 @@
1
1
  <pre style="font-size: 12px; padding: 10px; border: 1px solid #e1e1e8; background-color:#f5f5f5">
2
- <%= @backtrace.join("\n") %>
2
+ <%= @backtrace.join("\n") %>
3
3
  </pre>
@@ -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 -%>
@@ -5,6 +5,6 @@
5
5
  * Timestamp : <%= raw @timestamp %>
6
6
  * Server : <%= raw Socket.gethostname %>
7
7
  <% if defined?(Rails) && Rails.respond_to?(:root) %>
8
- * Rails root : <%= raw Rails.root %>
8
+ * Rails root : <%= raw Rails.root %>
9
9
  <% end %>
10
10
  * Process: <%= raw $$ %>
@@ -3,12 +3,12 @@
3
3
  <%= @exception.message %>
4
4
  <%= @backtrace.first %>
5
5
 
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 %>
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", :title => section).strip
14
+ title = render("title", title: section).strip
15
15
  [title, summary]
16
16
  end
17
-
18
17
  rescue Exception => e
19
- title = render("title", :title => section).strip
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", :title => section).strip
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", :title => section).strip
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,30 +19,32 @@ 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
- options[:body][:rails_root] = Rails.root
24
- end
25
- options[:body][:exception] = {:error_class => exception.class.to_s,
26
- :message => exception.message.inspect,
27
- :backtrace => exception.backtrace}
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 = {:url => request.original_url,
34
- :http_method => request.method,
35
- :ip_address => request.remote_ip,
36
- :parameters => request.filtered_parameters,
37
- :timestamp => Time.current }
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
41
44
  options[:body][:environment] = request.filtered_env
42
45
  end
43
- send_notice(exception, options, nil, @default_options) do |msg, opts|
44
- HTTParty.send(http_method, url, opts)
46
+ send_notice(exception, options, nil, @default_options) do |_, _|
47
+ HTTParty.send(http_method, url, options)
45
48
  end
46
49
  end
47
50
  end
@@ -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 "Creates a ExceptionNotification initializer."
6
+ desc 'Creates a ExceptionNotification initializer.'
5
7
 
6
- source_root File.expand_path('../templates', __FILE__)
7
- class_option :resque, :type => :boolean, :desc => 'Add support for sending notifications when errors occur in Resque jobs.'
8
- class_option :sidekiq, :type => :boolean, :desc => 'Add support for sending notifications when errors occur in Sidekiq jobs.'
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
@@ -13,7 +13,7 @@ Resque::Failure.backend = Resque::Failure::Multiple
13
13
 
14
14
  ExceptionNotification.configure do |config|
15
15
  # Ignore additional exception types.
16
- # ActiveRecord::RecordNotFound, AbstractController::ActionNotFound and ActionController::RoutingError are already added.
16
+ # ActiveRecord::RecordNotFound, Mongoid::Errors::DocumentNotFound, AbstractController::ActionNotFound and ActionController::RoutingError are already added.
17
17
  # config.ignored_exceptions += %w{ActionView::TemplateError CustomError}
18
18
 
19
19
  # Adds a condition to decide when an exception must be ignored or not.
@@ -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
- :email_prefix => "[ERROR] ",
30
- :sender_address => %{"Notifier" <notifier@example.com>},
31
- :exception_recipients => %w{exceptions@example.com}
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
- # :subdomain => 'my_subdomain',
37
- # :token => 'my_token',
38
- # :room_name => 'my_room'
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
- # :api_token => 'my_token',
44
- # :room_name => 'my_room'
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
- # :url => 'http://example.com:5555/hubot/path',
50
- # :http_method => :post
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
- test "should ignore \"X-Cascade\" header by default" do
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 "should notify on \"X-Cascade\" = \"pass\" if ignore_cascade_pass option is false" do
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, :ignore_cascade_pass => false).call({})
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,44 +1,51 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
- require 'tinder'
3
4
 
4
- class CampfireNotifierTest < ActiveSupport::TestCase
5
+ # silence_warnings trick around require can be removed once
6
+ # https://github.com/collectiveidea/tinder/pull/77
7
+ # gets merged and released
8
+ silence_warnings do
9
+ require 'tinder'
10
+ end
5
11
 
6
- test "should send campfire notification if properly configured" do
12
+ class CampfireNotifierTest < ActiveSupport::TestCase
13
+ test 'should send campfire notification if properly configured' do
7
14
  ExceptionNotifier::CampfireNotifier.stubs(:new).returns(Object.new)
8
- campfire = ExceptionNotifier::CampfireNotifier.new({:subdomain => 'test', :token => 'test_token', :room_name => 'test_room'})
15
+ campfire = ExceptionNotifier::CampfireNotifier.new(subdomain: 'test', token: 'test_token', room_name: 'test_room')
9
16
  campfire.stubs(:call).returns(fake_notification)
10
17
  notif = campfire.call(fake_exception)
11
18
 
12
19
  assert !notif[:message].empty?
13
20
  assert_equal notif[:message][:type], 'PasteMessage'
14
- assert_includes notif[:message][:body], "A new exception occurred:"
15
- assert_includes notif[:message][:body], "divided by 0"
16
- assert_includes notif[:message][:body], "/exception_notification/test/campfire_test.rb:45"
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'
17
24
  end
18
25
 
19
- test "should send campfire notification without backtrace info if properly configured" do
26
+ test 'should send campfire notification without backtrace info if properly configured' do
20
27
  ExceptionNotifier::CampfireNotifier.stubs(:new).returns(Object.new)
21
- campfire = ExceptionNotifier::CampfireNotifier.new({:subdomain => 'test', :token => 'test_token', :room_name => 'test_room'})
28
+ campfire = ExceptionNotifier::CampfireNotifier.new(subdomain: 'test', token: 'test_token', room_name: 'test_room')
22
29
  campfire.stubs(:call).returns(fake_notification_without_backtrace)
23
30
  notif = campfire.call(fake_exception_without_backtrace)
24
31
 
25
32
  assert !notif[:message].empty?
26
33
  assert_equal notif[:message][:type], 'PasteMessage'
27
- assert_includes notif[:message][:body], "A new exception occurred:"
28
- assert_includes notif[:message][:body], "my custom error"
34
+ assert_includes notif[:message][:body], 'A new exception occurred:'
35
+ assert_includes notif[:message][:body], 'my custom error'
29
36
  end
30
37
 
31
- test "should not send campfire notification if badly configured" do
32
- wrong_params = {:subdomain => 'test', :token => 'bad_token', :room_name => 'test_room'}
33
- Tinder::Campfire.stubs(:new).with('test', {:token => 'bad_token'}).returns(nil)
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)
34
41
  campfire = ExceptionNotifier::CampfireNotifier.new(wrong_params)
35
42
 
36
43
  assert_nil campfire.room
37
44
  assert_nil campfire.call(fake_exception)
38
45
  end
39
46
 
40
- test "should not send campfire notification if config attr missing" do
41
- wrong_params = {:subdomain => 'test', :room_name => 'test_room'}
47
+ test 'should not send campfire notification if config attr missing' do
48
+ wrong_params = { subdomain: 'test', room_name: 'test_room' }
42
49
  Tinder::Campfire.stubs(:new).with('test', {}).returns(nil)
43
50
  campfire = ExceptionNotifier::CampfireNotifier.new(wrong_params)
44
51
 
@@ -46,21 +53,34 @@ class CampfireNotifierTest < ActiveSupport::TestCase
46
53
  assert_nil campfire.call(fake_exception)
47
54
  end
48
55
 
49
- test "should call pre/post_callback if specified" do
50
- pre_callback_called, post_callback_called = 0,0
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
51
73
  Tinder::Campfire.stubs(:new).returns(Object.new)
52
74
 
53
75
  campfire = ExceptionNotifier::CampfireNotifier.new(
54
- {
55
- :subdomain => 'test',
56
- :token => 'test_token',
57
- :room_name => 'test_room',
58
- :pre_callback => proc { |opts, notifier, backtrace, message, message_opts|
59
- pre_callback_called += 1
60
- },
61
- :post_callback => proc { |opts, notifier, backtrace, message, message_opts|
62
- post_callback_called += 1
63
- }
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
64
84
  }
65
85
  )
66
86
  campfire.room = Object.new
@@ -73,24 +93,31 @@ class CampfireNotifierTest < ActiveSupport::TestCase
73
93
  private
74
94
 
75
95
  def fake_notification
76
- {:message => {:type => 'PasteMessage',
77
- :body => "A new exception occurred: 'divided by 0' on '/Users/sebastian/exception_notification/test/campfire_test.rb:45:in `/'"
78
- }
96
+ {
97
+ message: {
98
+ type: 'PasteMessage',
99
+ body: fake_notification_body
100
+ }
79
101
  }
80
102
  end
81
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
+
82
109
  def fake_exception
83
- exception = begin
84
- 5/0
85
- rescue Exception => e
86
- e
87
- end
110
+ 5 / 0
111
+ rescue StandardError => e
112
+ e
88
113
  end
89
114
 
90
115
  def fake_notification_without_backtrace
91
- {:message => {:type => 'PasteMessage',
92
- :body => "A new exception occurred: 'my custom error'"
93
- }
116
+ {
117
+ message: {
118
+ type: 'PasteMessage',
119
+ body: "A new exception occurred: 'my custom error'"
120
+ }
94
121
  }
95
122
  end
96
123