exception_notification_more_info 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +7 -0
  2. data/Appraisals +7 -0
  3. data/CHANGELOG.rdoc +141 -0
  4. data/CODE_OF_CONDUCT.md +22 -0
  5. data/CONTRIBUTING.md +42 -0
  6. data/Gemfile +3 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +839 -0
  9. data/Rakefile +23 -0
  10. data/examples/sinatra/Gemfile +8 -0
  11. data/examples/sinatra/Gemfile.lock +95 -0
  12. data/examples/sinatra/Procfile +2 -0
  13. data/examples/sinatra/README.md +11 -0
  14. data/examples/sinatra/config.ru +3 -0
  15. data/examples/sinatra/sinatra_app.rb +32 -0
  16. data/exception_notification_more_info.gemspec +34 -0
  17. data/gemfiles/rails4_0.gemfile +7 -0
  18. data/gemfiles/rails4_1.gemfile +7 -0
  19. data/gemfiles/rails4_2.gemfile +7 -0
  20. data/lib/exception_notification.rb +11 -0
  21. data/lib/exception_notification/rack.rb +59 -0
  22. data/lib/exception_notification/rails.rb +8 -0
  23. data/lib/exception_notification/resque.rb +24 -0
  24. data/lib/exception_notification/sidekiq.rb +31 -0
  25. data/lib/exception_notifier.rb +121 -0
  26. data/lib/exception_notifier/base_notifier.rb +25 -0
  27. data/lib/exception_notifier/campfire_notifier.rb +36 -0
  28. data/lib/exception_notifier/email_notifier.rb +204 -0
  29. data/lib/exception_notifier/hipchat_notifier.rb +45 -0
  30. data/lib/exception_notifier/irc_notifier.rb +51 -0
  31. data/lib/exception_notifier/modules/backtrace_cleaner.rb +13 -0
  32. data/lib/exception_notifier/notifier.rb +16 -0
  33. data/lib/exception_notifier/slack_notifier.rb +73 -0
  34. data/lib/exception_notifier/views/exception_notifier/_backtrace.html.erb +3 -0
  35. data/lib/exception_notifier/views/exception_notifier/_backtrace.text.erb +1 -0
  36. data/lib/exception_notifier/views/exception_notifier/_data.html.erb +6 -0
  37. data/lib/exception_notifier/views/exception_notifier/_data.text.erb +1 -0
  38. data/lib/exception_notifier/views/exception_notifier/_environment.html.erb +10 -0
  39. data/lib/exception_notifier/views/exception_notifier/_environment.text.erb +5 -0
  40. data/lib/exception_notifier/views/exception_notifier/_request.html.erb +36 -0
  41. data/lib/exception_notifier/views/exception_notifier/_request.text.erb +10 -0
  42. data/lib/exception_notifier/views/exception_notifier/_session.html.erb +10 -0
  43. data/lib/exception_notifier/views/exception_notifier/_session.text.erb +2 -0
  44. data/lib/exception_notifier/views/exception_notifier/_title.html.erb +3 -0
  45. data/lib/exception_notifier/views/exception_notifier/_title.text.erb +3 -0
  46. data/lib/exception_notifier/views/exception_notifier/background_exception_notification.html.erb +53 -0
  47. data/lib/exception_notifier/views/exception_notifier/background_exception_notification.text.erb +14 -0
  48. data/lib/exception_notifier/views/exception_notifier/exception_notification.html.erb +54 -0
  49. data/lib/exception_notifier/views/exception_notifier/exception_notification.text.erb +24 -0
  50. data/lib/exception_notifier/webhook_notifier.rb +47 -0
  51. data/lib/generators/exception_notification/install_generator.rb +15 -0
  52. data/lib/generators/exception_notification/templates/exception_notification.rb +53 -0
  53. data/test/dummy/.gitignore +4 -0
  54. data/test/dummy/Gemfile +34 -0
  55. data/test/dummy/Gemfile.lock +137 -0
  56. data/test/dummy/Rakefile +7 -0
  57. data/test/dummy/app/controllers/application_controller.rb +3 -0
  58. data/test/dummy/app/controllers/posts_controller.rb +30 -0
  59. data/test/dummy/app/helpers/application_helper.rb +2 -0
  60. data/test/dummy/app/helpers/posts_helper.rb +2 -0
  61. data/test/dummy/app/models/post.rb +2 -0
  62. data/test/dummy/app/views/exception_notifier/_new_bkg_section.html.erb +1 -0
  63. data/test/dummy/app/views/exception_notifier/_new_bkg_section.text.erb +1 -0
  64. data/test/dummy/app/views/exception_notifier/_new_section.html.erb +1 -0
  65. data/test/dummy/app/views/exception_notifier/_new_section.text.erb +1 -0
  66. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  67. data/test/dummy/app/views/posts/_form.html.erb +0 -0
  68. data/test/dummy/app/views/posts/new.html.erb +0 -0
  69. data/test/dummy/app/views/posts/show.html.erb +0 -0
  70. data/test/dummy/config.ru +4 -0
  71. data/test/dummy/config/application.rb +42 -0
  72. data/test/dummy/config/boot.rb +6 -0
  73. data/test/dummy/config/database.yml +22 -0
  74. data/test/dummy/config/environment.rb +17 -0
  75. data/test/dummy/config/environments/development.rb +25 -0
  76. data/test/dummy/config/environments/production.rb +50 -0
  77. data/test/dummy/config/environments/test.rb +38 -0
  78. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  79. data/test/dummy/config/initializers/inflections.rb +10 -0
  80. data/test/dummy/config/initializers/mime_types.rb +5 -0
  81. data/test/dummy/config/initializers/secret_token.rb +8 -0
  82. data/test/dummy/config/initializers/session_store.rb +8 -0
  83. data/test/dummy/config/locales/en.yml +5 -0
  84. data/test/dummy/config/routes.rb +3 -0
  85. data/test/dummy/db/migrate/20110729022608_create_posts.rb +15 -0
  86. data/test/dummy/db/schema.rb +24 -0
  87. data/test/dummy/db/seeds.rb +7 -0
  88. data/test/dummy/lib/tasks/.gitkeep +0 -0
  89. data/test/dummy/public/404.html +26 -0
  90. data/test/dummy/public/422.html +26 -0
  91. data/test/dummy/public/500.html +26 -0
  92. data/test/dummy/public/favicon.ico +0 -0
  93. data/test/dummy/public/images/rails.png +0 -0
  94. data/test/dummy/public/index.html +239 -0
  95. data/test/dummy/public/javascripts/application.js +2 -0
  96. data/test/dummy/public/javascripts/controls.js +965 -0
  97. data/test/dummy/public/javascripts/dragdrop.js +974 -0
  98. data/test/dummy/public/javascripts/effects.js +1123 -0
  99. data/test/dummy/public/javascripts/prototype.js +6001 -0
  100. data/test/dummy/public/javascripts/rails.js +191 -0
  101. data/test/dummy/public/robots.txt +5 -0
  102. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  103. data/test/dummy/public/stylesheets/scaffold.css +56 -0
  104. data/test/dummy/script/rails +6 -0
  105. data/test/dummy/test/fixtures/posts.yml +11 -0
  106. data/test/dummy/test/functional/posts_controller_test.rb +224 -0
  107. data/test/dummy/test/test_helper.rb +13 -0
  108. data/test/exception_notification/rack_test.rb +20 -0
  109. data/test/exception_notifier/campfire_notifier_test.rb +100 -0
  110. data/test/exception_notifier/email_notifier_test.rb +185 -0
  111. data/test/exception_notifier/hipchat_notifier_test.rb +177 -0
  112. data/test/exception_notifier/irc_notifier_test.rb +121 -0
  113. data/test/exception_notifier/sidekiq_test.rb +27 -0
  114. data/test/exception_notifier/slack_notifier_test.rb +179 -0
  115. data/test/exception_notifier/webhook_notifier_test.rb +68 -0
  116. data/test/exception_notifier_test.rb +103 -0
  117. data/test/test_helper.rb +18 -0
  118. metadata +428 -0
@@ -0,0 +1,13 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path('../../config/environment', __FILE__)
3
+ require 'rails/test_help'
4
+
5
+ class ActiveSupport::TestCase
6
+ # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
7
+ #
8
+ # Note: You'll currently still have to declare fixtures explicitly in integration tests
9
+ # -- they do not yet inherit this setting
10
+ fixtures :all
11
+
12
+ # Add more helper methods to be used by all tests here...
13
+ end
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+
3
+ class RackTest < ActiveSupport::TestCase
4
+
5
+ setup do
6
+ @pass_app = Object.new
7
+ @pass_app.stubs(:call).returns([nil, { 'X-Cascade' => 'pass' }, nil])
8
+ end
9
+
10
+ test "should ignore \"X-Cascade\" header by default" do
11
+ ExceptionNotifier.expects(:notify_exception).never
12
+ ExceptionNotification::Rack.new(@pass_app).call({})
13
+ end
14
+
15
+ test "should notify on \"X-Cascade\" = \"pass\" if ignore_cascade_pass option is false" do
16
+ ExceptionNotifier.expects(:notify_exception).once
17
+ ExceptionNotification::Rack.new(@pass_app, :ignore_cascade_pass => false).call({})
18
+ end
19
+
20
+ end
@@ -0,0 +1,100 @@
1
+ require 'test_helper'
2
+ require 'tinder'
3
+
4
+ class CampfireNotifierTest < ActiveSupport::TestCase
5
+
6
+ test "should send campfire notification if properly configured" do
7
+ ExceptionNotifier::CampfireNotifier.stubs(:new).returns(Object.new)
8
+ campfire = ExceptionNotifier::CampfireNotifier.new({:subdomain => 'test', :token => 'test_token', :room_name => 'test_room'})
9
+ campfire.stubs(:call).returns(fake_notification)
10
+ notif = campfire.call(fake_exception)
11
+
12
+ assert !notif[:message].empty?
13
+ 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"
17
+ end
18
+
19
+ test "should send campfire notification without backtrace info if properly configured" do
20
+ ExceptionNotifier::CampfireNotifier.stubs(:new).returns(Object.new)
21
+ campfire = ExceptionNotifier::CampfireNotifier.new({:subdomain => 'test', :token => 'test_token', :room_name => 'test_room'})
22
+ campfire.stubs(:call).returns(fake_notification_without_backtrace)
23
+ notif = campfire.call(fake_exception_without_backtrace)
24
+
25
+ assert !notif[:message].empty?
26
+ 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"
29
+ end
30
+
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)
34
+ campfire = ExceptionNotifier::CampfireNotifier.new(wrong_params)
35
+
36
+ assert_nil campfire.room
37
+ assert_nil campfire.call(fake_exception)
38
+ end
39
+
40
+ test "should not send campfire notification if config attr missing" do
41
+ wrong_params = {:subdomain => 'test', :room_name => 'test_room'}
42
+ Tinder::Campfire.stubs(:new).with('test', {}).returns(nil)
43
+ campfire = ExceptionNotifier::CampfireNotifier.new(wrong_params)
44
+
45
+ assert_nil campfire.room
46
+ assert_nil campfire.call(fake_exception)
47
+ end
48
+
49
+ test "should call pre/post_callback if specified" do
50
+ pre_callback_called, post_callback_called = 0,0
51
+ Tinder::Campfire.stubs(:new).returns(Object.new)
52
+
53
+ 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
+ }
64
+ }
65
+ )
66
+ campfire.room = Object.new
67
+ campfire.room.stubs(:paste).returns(fake_notification)
68
+ campfire.call(fake_exception)
69
+ assert_equal(1, pre_callback_called)
70
+ assert_equal(1, post_callback_called)
71
+ end
72
+
73
+ private
74
+
75
+ 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
+ }
79
+ }
80
+ end
81
+
82
+ def fake_exception
83
+ exception = begin
84
+ 5/0
85
+ rescue Exception => e
86
+ e
87
+ end
88
+ end
89
+
90
+ def fake_notification_without_backtrace
91
+ {:message => {:type => 'PasteMessage',
92
+ :body => "A new exception occurred: 'my custom error'"
93
+ }
94
+ }
95
+ end
96
+
97
+ def fake_exception_without_backtrace
98
+ StandardError.new('my custom error')
99
+ end
100
+ end
@@ -0,0 +1,185 @@
1
+ require 'test_helper'
2
+ require 'action_mailer'
3
+
4
+ class EmailNotifierTest < ActiveSupport::TestCase
5
+ setup do
6
+ Time.stubs(:current).returns('Sat, 20 Apr 2013 20:58:55 UTC +00:00')
7
+ @email_notifier = ExceptionNotifier.registered_exception_notifier(:email)
8
+ begin
9
+ 1/0
10
+ rescue => e
11
+ @exception = e
12
+ @mail = @email_notifier.create_email(@exception,
13
+ :data => {:job => 'DivideWorkerJob', :payload => '1/0', :message => 'My Custom Message'})
14
+ end
15
+ end
16
+
17
+ test "should call pre/post_callback if specified" do
18
+ assert_equal @email_notifier.options[:pre_callback_called], 1
19
+ assert_equal @email_notifier.options[:post_callback_called], 1
20
+ end
21
+
22
+ test "should have default sender address overridden" do
23
+ assert_equal @email_notifier.sender_address, %("Dummy Notifier" <dummynotifier@example.com>)
24
+ end
25
+
26
+ test "should have default exception recipients overridden" do
27
+ assert_equal @email_notifier.exception_recipients, %w(dummyexceptions@example.com)
28
+ end
29
+
30
+ test "should have default email prefix overridden" do
31
+ assert_equal @email_notifier.email_prefix, "[Dummy ERROR] "
32
+ end
33
+
34
+ test "should have default email headers overridden" do
35
+ assert_equal @email_notifier.email_headers, { "X-Custom-Header" => "foobar"}
36
+ end
37
+
38
+ test "should have default sections overridden" do
39
+ for section in %w(new_section request session environment backtrace)
40
+ assert_includes @email_notifier.sections, section
41
+ end
42
+ end
43
+
44
+ test "should have default background sections" do
45
+ for section in %w(new_bkg_section backtrace data)
46
+ assert_includes @email_notifier.background_sections, section
47
+ end
48
+ end
49
+
50
+ test "should have email format by default" do
51
+ assert_equal @email_notifier.email_format, :text
52
+ end
53
+
54
+ test "should have verbose subject by default" do
55
+ assert @email_notifier.verbose_subject
56
+ end
57
+
58
+ test "should have normalize_subject false by default" do
59
+ refute @email_notifier.normalize_subject
60
+ end
61
+
62
+ test "should have delivery_method nil by default" do
63
+ assert_nil @email_notifier.delivery_method
64
+ end
65
+
66
+ test "should have mailer_settings nil by default" do
67
+ assert_nil @email_notifier.mailer_settings
68
+ end
69
+
70
+ test "should have mailer_parent by default" do
71
+ assert_equal @email_notifier.mailer_parent, 'ActionMailer::Base'
72
+ end
73
+
74
+ test "should have template_path by default" do
75
+ assert_equal @email_notifier.template_path, 'exception_notifier'
76
+ end
77
+
78
+ test "should normalize multiple digits into one N" do
79
+ assert_equal 'N foo N bar N baz N',
80
+ ExceptionNotifier::EmailNotifier.normalize_digits('1 foo 12 bar 123 baz 1234')
81
+ end
82
+
83
+ test "mail should be plain text and UTF-8 enconded by default" do
84
+ assert_equal @mail.content_type, "text/plain; charset=UTF-8"
85
+ end
86
+
87
+ test "should have raised an exception" do
88
+ refute_nil @exception
89
+ end
90
+
91
+ test "should have generated a notification email" do
92
+ refute_nil @mail
93
+ end
94
+
95
+ test "mail should have a from address set" do
96
+ assert_equal @mail.from, ["dummynotifier@example.com"]
97
+ end
98
+
99
+ test "mail should have a to address set" do
100
+ assert_equal @mail.to, ["dummyexceptions@example.com"]
101
+ end
102
+
103
+ test "mail should have a descriptive subject" do
104
+ assert_match /^\[Dummy ERROR\]\s+\(ZeroDivisionError\) "divided by 0"$/, @mail.subject
105
+ end
106
+
107
+ test "mail should say exception was raised in background at show timestamp" do
108
+ assert_includes @mail.encoded, "A ZeroDivisionError occurred in background at #{Time.current}"
109
+ end
110
+
111
+ test "mail should prefix exception class with 'an' instead of 'a' when it starts with a vowel" do
112
+ begin
113
+ raise ActiveRecord::RecordNotFound
114
+ rescue => e
115
+ @vowel_exception = e
116
+ @vowel_mail = @email_notifier.create_email(@vowel_exception)
117
+ end
118
+
119
+ assert_includes @vowel_mail.encoded, "An ActiveRecord::RecordNotFound occurred in background at #{Time.current}"
120
+ end
121
+
122
+ test "mail should contain backtrace in body" do
123
+ assert @mail.encoded.include?("test/exception_notifier/email_notifier_test.rb:9"), "\n#{@mail.inspect}"
124
+ end
125
+
126
+ test "mail should contain data in body" do
127
+ assert_includes @mail.encoded, '* data:'
128
+ assert_includes @mail.encoded, ':payload=>"1/0"'
129
+ assert_includes @mail.encoded, ':job=>"DivideWorkerJob"'
130
+ assert_includes @mail.encoded, "My Custom Message"
131
+ end
132
+
133
+ test "mail should not contain any attachments" do
134
+ assert_equal @mail.attachments, []
135
+ end
136
+
137
+ test "should not send notification if one of ignored exceptions" do
138
+ begin
139
+ raise ActiveRecord::RecordNotFound
140
+ rescue => e
141
+ @ignored_exception = e
142
+ unless ExceptionNotifier.ignored_exceptions.include?(@ignored_exception.class.name)
143
+ @ignored_mail = @email_notifier.create_email(@ignored_exception)
144
+ end
145
+ end
146
+
147
+ assert_equal @ignored_exception.class.inspect, "ActiveRecord::RecordNotFound"
148
+ assert_nil @ignored_mail
149
+ end
150
+
151
+ test "should encode environment strings" do
152
+ email_notifier = ExceptionNotifier::EmailNotifier.new(
153
+ :sender_address => "<dummynotifier@example.com>",
154
+ :exception_recipients => %w{dummyexceptions@example.com},
155
+ :deliver_with => :deliver_now
156
+ )
157
+
158
+ mail = email_notifier.create_email(
159
+ @exception,
160
+ :env => {
161
+ "REQUEST_METHOD" => "GET",
162
+ "rack.input" => "",
163
+ "invalid_encoding" => "R\xC3\xA9sum\xC3\xA9".force_encoding(Encoding::ASCII),
164
+ },
165
+ :email_format => :text
166
+ )
167
+
168
+ assert_match /invalid_encoding\s+: R__sum__/, mail.encoded
169
+ end
170
+
171
+ test "should send email using ActionMailer" do
172
+ ActionMailer::Base.deliveries.clear
173
+
174
+ email_notifier = ExceptionNotifier::EmailNotifier.new(
175
+ :email_prefix => '[Dummy ERROR] ',
176
+ :sender_address => %{"Dummy Notifier" <dummynotifier@example.com>},
177
+ :exception_recipients => %w{dummyexceptions@example.com},
178
+ :delivery_method => :test
179
+ )
180
+
181
+ email_notifier.call(@exception)
182
+
183
+ assert_equal 1, ActionMailer::Base.deliveries.count
184
+ end
185
+ end
@@ -0,0 +1,177 @@
1
+ require 'test_helper'
2
+ require 'hipchat'
3
+
4
+ class HipchatNotifierTest < ActiveSupport::TestCase
5
+
6
+ test "should send hipchat notification if properly configured" do
7
+ options = {
8
+ :api_token => 'good_token',
9
+ :room_name => 'room_name',
10
+ :color => 'yellow',
11
+ }
12
+
13
+ HipChat::Room.any_instance.expects(:send).with('Exception', fake_body, { :color => 'yellow' })
14
+
15
+ hipchat = ExceptionNotifier::HipchatNotifier.new(options)
16
+ hipchat.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
+ options = {
22
+ :api_token => 'good_token',
23
+ :room_name => 'room_name',
24
+ :color => 'yellow',
25
+ :pre_callback => proc { |*| pre_callback_called += 1},
26
+ :post_callback => proc { |*| post_callback_called += 1}
27
+ }
28
+
29
+ HipChat::Room.any_instance.expects(:send).with('Exception', fake_body, { :color => 'yellow' }.merge(options.except(:api_token, :room_name)))
30
+
31
+ hipchat = ExceptionNotifier::HipchatNotifier.new(options)
32
+ hipchat.call(fake_exception)
33
+ assert_equal(1, pre_callback_called)
34
+ assert_equal(1, post_callback_called)
35
+ end
36
+
37
+ test "should send hipchat notification without backtrace info if properly configured" do
38
+ options = {
39
+ :api_token => 'good_token',
40
+ :room_name => 'room_name',
41
+ :color => 'yellow',
42
+ }
43
+
44
+ HipChat::Room.any_instance.expects(:send).with('Exception', fake_body_without_backtrace, { :color => 'yellow' })
45
+
46
+ hipchat = ExceptionNotifier::HipchatNotifier.new(options)
47
+ hipchat.call(fake_exception_without_backtrace)
48
+ end
49
+
50
+ test "should allow custom from value if set" do
51
+ options = {
52
+ :api_token => 'good_token',
53
+ :room_name => 'room_name',
54
+ :from => 'TrollFace',
55
+ }
56
+
57
+ HipChat::Room.any_instance.expects(:send).with('TrollFace', fake_body, { :color => 'red' })
58
+
59
+ hipchat = ExceptionNotifier::HipchatNotifier.new(options)
60
+ hipchat.call(fake_exception)
61
+ end
62
+
63
+ test "should not send hipchat notification if badly configured" do
64
+ wrong_params = {
65
+ :api_token => 'bad_token',
66
+ :room_name => 'test_room'
67
+ }
68
+
69
+ HipChat::Client.stubs(:new).with('bad_token', {:api_version => 'v1'}).returns(nil)
70
+
71
+ hipchat = ExceptionNotifier::HipchatNotifier.new(wrong_params)
72
+ assert_nil hipchat.room
73
+ end
74
+
75
+ test "should not send hipchat notification if api_key is missing" do
76
+ wrong_params = {:room_name => 'test_room'}
77
+
78
+ HipChat::Client.stubs(:new).with(nil, {:api_version => 'v1'}).returns(nil)
79
+
80
+ hipchat = ExceptionNotifier::HipchatNotifier.new(wrong_params)
81
+ assert_nil hipchat.room
82
+ end
83
+
84
+ test "should not send hipchat notification if room_name is missing" do
85
+ wrong_params = {:api_token => 'good_token'}
86
+
87
+ HipChat::Client.stubs(:new).with('good_token', {:api_version => 'v1'}).returns({})
88
+
89
+ hipchat = ExceptionNotifier::HipchatNotifier.new(wrong_params)
90
+ assert_nil hipchat.room
91
+ end
92
+
93
+ test "should send hipchat notification with message_template" do
94
+ options = {
95
+ :api_token => 'good_token',
96
+ :room_name => 'room_name',
97
+ :color => 'yellow',
98
+ :message_template => ->(exception) { "This is custom message: '#{exception.message}'" }
99
+ }
100
+
101
+ HipChat::Room.any_instance.expects(:send).with('Exception', "This is custom message: '#{fake_exception.message}'", { :color => 'yellow' })
102
+
103
+ hipchat = ExceptionNotifier::HipchatNotifier.new(options)
104
+ hipchat.call(fake_exception)
105
+ end
106
+
107
+ test "should send hipchat notification with HTML-escaped meessage if using default message_template" do
108
+ options = {
109
+ :api_token => 'good_token',
110
+ :room_name => 'room_name',
111
+ :color => 'yellow',
112
+ }
113
+
114
+ exception = fake_exception_with_html_characters
115
+ body = "A new exception occurred: '#{Rack::Utils.escape_html(exception.message)}' on '#{exception.backtrace.first}'"
116
+
117
+ HipChat::Room.any_instance.expects(:send).with('Exception', body, { :color => 'yellow' })
118
+
119
+ hipchat = ExceptionNotifier::HipchatNotifier.new(options)
120
+ hipchat.call(exception)
121
+ end
122
+
123
+ test "should use APIv1 if api_version is not specified" do
124
+ options = {
125
+ :api_token => 'good_token',
126
+ :room_name => 'room_name',
127
+ }
128
+
129
+ HipChat::Client.stubs(:new).with('good_token', {:api_version => 'v1'}).returns({})
130
+
131
+ hipchat = ExceptionNotifier::HipchatNotifier.new(options)
132
+ hipchat.call(fake_exception)
133
+ end
134
+
135
+ test "should use APIv2 when specified" do
136
+ options = {
137
+ :api_token => 'good_token',
138
+ :room_name => 'room_name',
139
+ :api_version => 'v2',
140
+ }
141
+
142
+ HipChat::Client.stubs(:new).with('good_token', {:api_version => 'v2'}).returns({})
143
+
144
+ hipchat = ExceptionNotifier::HipchatNotifier.new(options)
145
+ hipchat.call(fake_exception)
146
+ end
147
+
148
+ private
149
+
150
+ def fake_body
151
+ "A new exception occurred: '#{fake_exception.message}' on '#{fake_exception.backtrace.first}'"
152
+ end
153
+
154
+ def fake_exception
155
+ exception = begin
156
+ 5/0
157
+ rescue Exception => e
158
+ e
159
+ end
160
+ end
161
+
162
+ def fake_exception_with_html_characters
163
+ exception = begin
164
+ raise StandardError.new('an error with <html> characters')
165
+ rescue Exception => e
166
+ e
167
+ end
168
+ end
169
+
170
+ def fake_body_without_backtrace
171
+ "A new exception occurred: '#{fake_exception_without_backtrace.message}'"
172
+ end
173
+
174
+ def fake_exception_without_backtrace
175
+ StandardError.new('my custom error')
176
+ end
177
+ end