exception_notification 4.2.0 → 4.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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