square-hoptoad_notifier 2.4.8

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 (52) hide show
  1. data/CHANGELOG +427 -0
  2. data/INSTALL +25 -0
  3. data/MIT-LICENSE +22 -0
  4. data/README.md +435 -0
  5. data/README_FOR_HEROKU_ADDON.md +93 -0
  6. data/Rakefile +227 -0
  7. data/SUPPORTED_RAILS_VERSIONS +10 -0
  8. data/TESTING.rdoc +8 -0
  9. data/generators/hoptoad/hoptoad_generator.rb +88 -0
  10. data/generators/hoptoad/lib/insert_commands.rb +34 -0
  11. data/generators/hoptoad/lib/rake_commands.rb +24 -0
  12. data/generators/hoptoad/templates/capistrano_hook.rb +6 -0
  13. data/generators/hoptoad/templates/hoptoad_notifier_tasks.rake +25 -0
  14. data/generators/hoptoad/templates/initializer.rb +6 -0
  15. data/lib/hoptoad_notifier.rb +153 -0
  16. data/lib/hoptoad_notifier/backtrace.rb +99 -0
  17. data/lib/hoptoad_notifier/capistrano.rb +20 -0
  18. data/lib/hoptoad_notifier/configuration.rb +242 -0
  19. data/lib/hoptoad_notifier/notice.rb +337 -0
  20. data/lib/hoptoad_notifier/rack.rb +42 -0
  21. data/lib/hoptoad_notifier/rails.rb +41 -0
  22. data/lib/hoptoad_notifier/rails/action_controller_catcher.rb +30 -0
  23. data/lib/hoptoad_notifier/rails/controller_methods.rb +68 -0
  24. data/lib/hoptoad_notifier/rails/error_lookup.rb +33 -0
  25. data/lib/hoptoad_notifier/rails/javascript_notifier.rb +42 -0
  26. data/lib/hoptoad_notifier/rails3_tasks.rb +82 -0
  27. data/lib/hoptoad_notifier/railtie.rb +32 -0
  28. data/lib/hoptoad_notifier/sender.rb +83 -0
  29. data/lib/hoptoad_notifier/shared_tasks.rb +29 -0
  30. data/lib/hoptoad_notifier/tasks.rb +83 -0
  31. data/lib/hoptoad_notifier/user_informer.rb +23 -0
  32. data/lib/hoptoad_notifier/version.rb +3 -0
  33. data/lib/hoptoad_tasks.rb +44 -0
  34. data/lib/rails/generators/hoptoad/hoptoad_generator.rb +94 -0
  35. data/lib/templates/javascript_notifier.erb +13 -0
  36. data/lib/templates/rescue.erb +91 -0
  37. data/rails/init.rb +1 -0
  38. data/script/integration_test.rb +38 -0
  39. data/test/backtrace_test.rb +118 -0
  40. data/test/catcher_test.rb +331 -0
  41. data/test/configuration_test.rb +216 -0
  42. data/test/helper.rb +248 -0
  43. data/test/hoptoad_tasks_test.rb +152 -0
  44. data/test/javascript_notifier_test.rb +52 -0
  45. data/test/logger_test.rb +85 -0
  46. data/test/notice_test.rb +448 -0
  47. data/test/notifier_test.rb +222 -0
  48. data/test/rack_test.rb +58 -0
  49. data/test/rails_initializer_test.rb +36 -0
  50. data/test/sender_test.rb +161 -0
  51. data/test/user_informer_test.rb +29 -0
  52. metadata +225 -0
@@ -0,0 +1,222 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class NotifierTest < Test::Unit::TestCase
4
+
5
+ class OriginalException < Exception
6
+ end
7
+
8
+ class ContinuedException < Exception
9
+ end
10
+
11
+ include DefinesConstants
12
+
13
+ def setup
14
+ super
15
+ reset_config
16
+ end
17
+
18
+ def assert_sent(notice, notice_args)
19
+ assert_received(HoptoadNotifier::Notice, :new) {|expect| expect.with(has_entries(notice_args)) }
20
+ assert_received(notice, :to_xml)
21
+ assert_received(HoptoadNotifier.sender, :send_to_hoptoad) {|expect| expect.with(notice.to_xml) }
22
+ end
23
+
24
+ def set_public_env
25
+ HoptoadNotifier.configure { |config| config.environment_name = 'production' }
26
+ end
27
+
28
+ def set_development_env
29
+ HoptoadNotifier.configure { |config| config.environment_name = 'development' }
30
+ end
31
+
32
+ should "yield and save a configuration when configuring" do
33
+ yielded_configuration = nil
34
+ HoptoadNotifier.configure do |config|
35
+ yielded_configuration = config
36
+ end
37
+
38
+ assert_kind_of HoptoadNotifier::Configuration, yielded_configuration
39
+ assert_equal yielded_configuration, HoptoadNotifier.configuration
40
+ end
41
+
42
+ should "not remove existing config options when configuring twice" do
43
+ first_config = nil
44
+ HoptoadNotifier.configure do |config|
45
+ first_config = config
46
+ end
47
+ HoptoadNotifier.configure do |config|
48
+ assert_equal first_config, config
49
+ end
50
+ end
51
+
52
+ should "configure the sender" do
53
+ sender = stub_sender
54
+ HoptoadNotifier::Sender.stubs(:new => sender)
55
+ configuration = nil
56
+
57
+ HoptoadNotifier.configure { |yielded_config| configuration = yielded_config }
58
+
59
+ assert_received(HoptoadNotifier::Sender, :new) { |expect| expect.with(configuration) }
60
+ assert_equal sender, HoptoadNotifier.sender
61
+ end
62
+
63
+ should "create and send a notice for an exception" do
64
+ set_public_env
65
+ exception = build_exception
66
+ stub_sender!
67
+ notice = stub_notice!
68
+
69
+ HoptoadNotifier.notify(exception)
70
+
71
+ assert_sent notice, :exception => exception
72
+ end
73
+
74
+ should "create and send a notice for a hash" do
75
+ set_public_env
76
+ notice = stub_notice!
77
+ notice_args = { :error_message => 'uh oh' }
78
+ stub_sender!
79
+
80
+ HoptoadNotifier.notify(notice_args)
81
+
82
+ assert_sent(notice, notice_args)
83
+ end
84
+
85
+ should "create and sent a notice for an exception and hash" do
86
+ set_public_env
87
+ exception = build_exception
88
+ notice = stub_notice!
89
+ notice_args = { :error_message => 'uh oh' }
90
+ stub_sender!
91
+
92
+ HoptoadNotifier.notify(exception, notice_args)
93
+
94
+ assert_sent(notice, notice_args.merge(:exception => exception))
95
+ end
96
+
97
+ should "not create a notice in a development environment" do
98
+ set_development_env
99
+ sender = stub_sender!
100
+
101
+ HoptoadNotifier.notify(build_exception)
102
+ HoptoadNotifier.notify_or_ignore(build_exception)
103
+
104
+ assert_received(sender, :send_to_hoptoad) {|expect| expect.never }
105
+ end
106
+
107
+ should "not deliver an ignored exception when notifying implicitly" do
108
+ set_public_env
109
+ exception = build_exception
110
+ sender = stub_sender!
111
+ notice = stub_notice!
112
+ notice.stubs(:ignore? => true)
113
+
114
+ HoptoadNotifier.notify_or_ignore(exception)
115
+
116
+ assert_received(sender, :send_to_hoptoad) {|expect| expect.never }
117
+ end
118
+
119
+ should "deliver an ignored exception when notifying manually" do
120
+ set_public_env
121
+ exception = build_exception
122
+ sender = stub_sender!
123
+ notice = stub_notice!
124
+ notice.stubs(:ignore? => true)
125
+
126
+ HoptoadNotifier.notify(exception)
127
+
128
+ assert_sent(notice, :exception => exception)
129
+ end
130
+
131
+ should "pass config to created notices" do
132
+ exception = build_exception
133
+ config_opts = { 'one' => 'two', 'three' => 'four' }
134
+ notice = stub_notice!
135
+ stub_sender!
136
+ HoptoadNotifier.configuration = stub('config', :merge => config_opts, :public? => true)
137
+
138
+ HoptoadNotifier.notify(exception)
139
+
140
+ assert_received(HoptoadNotifier::Notice, :new) do |expect|
141
+ expect.with(has_entries(config_opts))
142
+ end
143
+ end
144
+
145
+ context "building notice JSON for an exception" do
146
+ setup do
147
+ @params = { :controller => "users", :action => "create" }
148
+ @exception = build_exception
149
+ @hash = HoptoadNotifier.build_lookup_hash_for(@exception, @params)
150
+ end
151
+
152
+ should "set action" do
153
+ assert_equal @params[:action], @hash[:action]
154
+ end
155
+
156
+ should "set controller" do
157
+ assert_equal @params[:controller], @hash[:component]
158
+ end
159
+
160
+ should "set line number" do
161
+ assert @hash[:line_number] =~ /\d+/
162
+ end
163
+
164
+ should "set file" do
165
+ assert_match /test\/helper\.rb$/, @hash[:file]
166
+ end
167
+
168
+ should "set rails_env to production" do
169
+ assert_equal 'production', @hash[:environment_name]
170
+ end
171
+
172
+ should "set error class" do
173
+ assert_equal 'RuntimeError', @hash[:error_class]
174
+ end
175
+
176
+ should "not set file or line number with no backtrace" do
177
+ @exception.stubs(:backtrace).returns([])
178
+
179
+ @hash = HoptoadNotifier.build_lookup_hash_for(@exception)
180
+
181
+ assert_nil @hash[:line_number]
182
+ assert_nil @hash[:file]
183
+ end
184
+
185
+ should "not set action or controller when not provided" do
186
+ @hash = HoptoadNotifier.build_lookup_hash_for(@exception)
187
+
188
+ assert_nil @hash[:action]
189
+ assert_nil @hash[:controller]
190
+ end
191
+
192
+ context "when an exception that provides #original_exception is raised" do
193
+ setup do
194
+ @exception.stubs(:original_exception).returns(begin
195
+ raise NotifierTest::OriginalException.new
196
+ rescue Exception => e
197
+ e
198
+ end)
199
+ end
200
+
201
+ should "unwrap exceptions that provide #original_exception" do
202
+ @hash = HoptoadNotifier.build_lookup_hash_for(@exception)
203
+ assert_equal "NotifierTest::OriginalException", @hash[:error_class]
204
+ end
205
+ end
206
+
207
+ context "when an exception that provides #continued_exception is raised" do
208
+ setup do
209
+ @exception.stubs(:continued_exception).returns(begin
210
+ raise NotifierTest::ContinuedException.new
211
+ rescue Exception => e
212
+ e
213
+ end)
214
+ end
215
+
216
+ should "unwrap exceptions that provide #continued_exception" do
217
+ @hash = HoptoadNotifier.build_lookup_hash_for(@exception)
218
+ assert_equal "NotifierTest::ContinuedException", @hash[:error_class]
219
+ end
220
+ end
221
+ end
222
+ end
data/test/rack_test.rb ADDED
@@ -0,0 +1,58 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class RackTest < Test::Unit::TestCase
4
+
5
+ should "call the upstream app with the environment" do
6
+ environment = { 'key' => 'value' }
7
+ app = lambda { |env| ['response', {}, env] }
8
+ stack = HoptoadNotifier::Rack.new(app)
9
+
10
+ response = stack.call(environment)
11
+
12
+ assert_equal ['response', {}, environment], response
13
+ end
14
+
15
+ should "deliver an exception raised while calling an upstream app" do
16
+ HoptoadNotifier.stubs(:notify_or_ignore)
17
+
18
+ exception = build_exception
19
+ environment = { 'key' => 'value' }
20
+ app = lambda do |env|
21
+ raise exception
22
+ end
23
+
24
+ begin
25
+ stack = HoptoadNotifier::Rack.new(app)
26
+ stack.call(environment)
27
+ rescue Exception => raised
28
+ assert_equal exception, raised
29
+ else
30
+ flunk "Didn't raise an exception"
31
+ end
32
+
33
+ assert_received(HoptoadNotifier, :notify_or_ignore) do |expect|
34
+ expect.with(exception, :rack_env => environment)
35
+ end
36
+ end
37
+
38
+ should "deliver an exception in rack.exception" do
39
+ HoptoadNotifier.stubs(:notify_or_ignore)
40
+ exception = build_exception
41
+ environment = { 'key' => 'value' }
42
+
43
+ response = [200, {}, ['okay']]
44
+ app = lambda do |env|
45
+ env['rack.exception'] = exception
46
+ response
47
+ end
48
+ stack = HoptoadNotifier::Rack.new(app)
49
+
50
+ actual_response = stack.call(environment)
51
+
52
+ assert_equal response, actual_response
53
+ assert_received(HoptoadNotifier, :notify_or_ignore) do |expect|
54
+ expect.with(exception, :rack_env => environment)
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ require 'hoptoad_notifier/rails'
4
+
5
+ class RailsInitializerTest < Test::Unit::TestCase
6
+ include DefinesConstants
7
+
8
+ should "trigger use of Rails' logger if logger isn't set and Rails' logger exists" do
9
+ rails = Module.new do
10
+ def self.logger
11
+ "RAILS LOGGER"
12
+ end
13
+ end
14
+ define_constant("Rails", rails)
15
+ HoptoadNotifier::Rails.initialize
16
+ assert_equal "RAILS LOGGER", HoptoadNotifier.logger
17
+ end
18
+
19
+ should "trigger use of Rails' default logger if logger isn't set and Rails.logger doesn't exist" do
20
+ define_constant("RAILS_DEFAULT_LOGGER", "RAILS DEFAULT LOGGER")
21
+
22
+ HoptoadNotifier::Rails.initialize
23
+ assert_equal "RAILS DEFAULT LOGGER", HoptoadNotifier.logger
24
+ end
25
+
26
+ should "allow overriding of the logger if already assigned" do
27
+ define_constant("RAILS_DEFAULT_LOGGER", "RAILS DEFAULT LOGGER")
28
+ HoptoadNotifier::Rails.initialize
29
+
30
+ HoptoadNotifier.configure(true) do |config|
31
+ config.logger = "OVERRIDDEN LOGGER"
32
+ end
33
+
34
+ assert_equal "OVERRIDDEN LOGGER", HoptoadNotifier.logger
35
+ end
36
+ end
@@ -0,0 +1,161 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class SenderTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ reset_config
7
+ end
8
+
9
+ def build_sender(opts = {})
10
+ config = HoptoadNotifier::Configuration.new
11
+ opts.each {|opt, value| config.send(:"#{opt}=", value) }
12
+ HoptoadNotifier::Sender.new(config)
13
+ end
14
+
15
+ def send_exception(args = {})
16
+ notice = args.delete(:notice) || build_notice_data
17
+ sender = args.delete(:sender) || build_sender(args)
18
+ sender.send_to_hoptoad(notice)
19
+ end
20
+
21
+ def stub_http(options = {})
22
+ response = stub(:body => options[:body] || 'body')
23
+ http = stub(:post => response,
24
+ :read_timeout= => nil,
25
+ :open_timeout= => nil,
26
+ :ca_file= => nil,
27
+ :verify_mode= => nil,
28
+ :use_ssl= => nil)
29
+ Net::HTTP.stubs(:new => http)
30
+ http
31
+ end
32
+
33
+ should "post to Hoptoad when using an HTTP proxy" do
34
+ response = stub(:body => 'body')
35
+ http = stub(:post => response,
36
+ :read_timeout= => nil,
37
+ :open_timeout= => nil,
38
+ :use_ssl= => nil)
39
+ proxy = stub(:new => http)
40
+ Net::HTTP.stubs(:Proxy => proxy)
41
+
42
+ url = "http://hoptoadapp.com:80#{HoptoadNotifier::Sender::NOTICES_URI}"
43
+ uri = URI.parse(url)
44
+
45
+ proxy_host = 'some.host'
46
+ proxy_port = 88
47
+ proxy_user = 'login'
48
+ proxy_pass = 'passwd'
49
+
50
+ send_exception(:proxy_host => proxy_host,
51
+ :proxy_port => proxy_port,
52
+ :proxy_user => proxy_user,
53
+ :proxy_pass => proxy_pass)
54
+ assert_received(http, :post) do |expect|
55
+ expect.with(uri.path, anything, HoptoadNotifier::HEADERS)
56
+ end
57
+ assert_received(Net::HTTP, :Proxy) do |expect|
58
+ expect.with(proxy_host, proxy_port, proxy_user, proxy_pass)
59
+ end
60
+ end
61
+
62
+ should "return the created group's id on successful posting" do
63
+ http = stub_http(:body => '<error-id type="integer">3799307</error-id>')
64
+ assert_equal "3799307", send_exception(:secure => false)
65
+ end
66
+
67
+ should "return nil on failed posting" do
68
+ http = stub_http
69
+ http.stubs(:post).raises(Errno::ECONNREFUSED)
70
+ assert_equal nil, send_exception(:secure => false)
71
+ end
72
+
73
+ should "not fail when posting and a timeout exception occurs" do
74
+ http = stub_http
75
+ http.stubs(:post).raises(TimeoutError)
76
+ assert_nothing_thrown do
77
+ send_exception(:secure => false)
78
+ end
79
+ end
80
+
81
+ should "not fail when posting and a connection refused exception occurs" do
82
+ http = stub_http
83
+ http.stubs(:post).raises(Errno::ECONNREFUSED)
84
+ assert_nothing_thrown do
85
+ send_exception(:secure => false)
86
+ end
87
+ end
88
+
89
+ should "not fail when posting any http exception occurs" do
90
+ http = stub_http
91
+ HoptoadNotifier::Sender::HTTP_ERRORS.each do |error|
92
+ http.stubs(:post).raises(error)
93
+ assert_nothing_thrown do
94
+ send_exception(:secure => false)
95
+ end
96
+ end
97
+ end
98
+
99
+ should "post to the right url for non-ssl" do
100
+ http = stub_http
101
+ url = "http://hoptoadapp.com:80#{HoptoadNotifier::Sender::NOTICES_URI}"
102
+ uri = URI.parse(url)
103
+ send_exception(:secure => false)
104
+ assert_received(http, :post) {|expect| expect.with(uri.path, anything, HoptoadNotifier::HEADERS) }
105
+ end
106
+
107
+ should "post to the right path for ssl" do
108
+ http = stub_http
109
+ send_exception(:secure => true)
110
+ assert_received(http, :post) {|expect| expect.with(HoptoadNotifier::Sender::NOTICES_URI, anything, HoptoadNotifier::HEADERS) }
111
+ end
112
+
113
+ should "default the open timeout to 2 seconds" do
114
+ http = stub_http
115
+ send_exception
116
+ assert_received(http, :open_timeout=) {|expect| expect.with(2) }
117
+ end
118
+
119
+ should "default the read timeout to 5 seconds" do
120
+ http = stub_http
121
+ send_exception
122
+ assert_received(http, :read_timeout=) {|expect| expect.with(5) }
123
+ end
124
+
125
+ should "allow override of the open timeout" do
126
+ http = stub_http
127
+ send_exception(:http_open_timeout => 4)
128
+ assert_received(http, :open_timeout=) {|expect| expect.with(4) }
129
+ end
130
+
131
+ should "allow override of the read timeout" do
132
+ http = stub_http
133
+ send_exception(:http_read_timeout => 10)
134
+ assert_received(http, :read_timeout=) {|expect| expect.with(10) }
135
+ end
136
+
137
+ should "connect to the right port for ssl" do
138
+ stub_http
139
+ send_exception(:secure => true)
140
+ assert_received(Net::HTTP, :new) {|expect| expect.with("hoptoadapp.com", 443) }
141
+ end
142
+
143
+ should "connect to the right port for non-ssl" do
144
+ stub_http
145
+ send_exception(:secure => false)
146
+ assert_received(Net::HTTP, :new) {|expect| expect.with("hoptoadapp.com", 80) }
147
+ end
148
+
149
+ should "use ssl if secure" do
150
+ stub_http
151
+ send_exception(:secure => true, :host => 'example.org')
152
+ assert_received(Net::HTTP, :new) {|expect| expect.with('example.org', 443) }
153
+ end
154
+
155
+ should "not use ssl if not secure" do
156
+ stub_http
157
+ send_exception(:secure => false, :host => 'example.org')
158
+ assert_received(Net::HTTP, :new) {|expect| expect.with('example.org', 80) }
159
+ end
160
+
161
+ end