errornot_notifier 0.1.0

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 (41) hide show
  1. data/INSTALL +25 -0
  2. data/MIT-LICENSE +22 -0
  3. data/README.rdoc +289 -0
  4. data/Rakefile +124 -0
  5. data/SUPPORTED_RAILS_VERSIONS +8 -0
  6. data/TESTING.rdoc +8 -0
  7. data/generators/hoptoad/hoptoad_generator.rb +55 -0
  8. data/generators/hoptoad/lib/insert_commands.rb +34 -0
  9. data/generators/hoptoad/lib/rake_commands.rb +24 -0
  10. data/generators/hoptoad/templates/capistrano_hook.rb +6 -0
  11. data/generators/hoptoad/templates/hoptoad_notifier_tasks.rake +5 -0
  12. data/generators/hoptoad/templates/initializer.rb +7 -0
  13. data/lib/hoptoad_notifier/backtrace.rb +99 -0
  14. data/lib/hoptoad_notifier/capistrano.rb +20 -0
  15. data/lib/hoptoad_notifier/configuration.rb +232 -0
  16. data/lib/hoptoad_notifier/notice.rb +287 -0
  17. data/lib/hoptoad_notifier/rack.rb +40 -0
  18. data/lib/hoptoad_notifier/rails/action_controller_catcher.rb +29 -0
  19. data/lib/hoptoad_notifier/rails/controller_methods.rb +59 -0
  20. data/lib/hoptoad_notifier/rails/error_lookup.rb +33 -0
  21. data/lib/hoptoad_notifier/rails.rb +37 -0
  22. data/lib/hoptoad_notifier/sender.rb +85 -0
  23. data/lib/hoptoad_notifier/tasks.rb +97 -0
  24. data/lib/hoptoad_notifier/version.rb +3 -0
  25. data/lib/hoptoad_notifier.rb +146 -0
  26. data/lib/hoptoad_tasks.rb +37 -0
  27. data/lib/templates/rescue.erb +91 -0
  28. data/rails/init.rb +1 -0
  29. data/script/integration_test.rb +38 -0
  30. data/test/backtrace_test.rb +118 -0
  31. data/test/catcher_test.rb +300 -0
  32. data/test/configuration_test.rb +208 -0
  33. data/test/helper.rb +232 -0
  34. data/test/hoptoad_tasks_test.rb +138 -0
  35. data/test/logger_test.rb +85 -0
  36. data/test/notice_test.rb +395 -0
  37. data/test/notifier_test.rb +222 -0
  38. data/test/rack_test.rb +58 -0
  39. data/test/rails_initializer_test.rb +36 -0
  40. data/test/sender_test.rb +123 -0
  41. metadata +164 -0
@@ -0,0 +1,395 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class NoticeTest < Test::Unit::TestCase
4
+
5
+ include DefinesConstants
6
+
7
+ def configure
8
+ returning HoptoadNotifier::Configuration.new do |config|
9
+ config.api_key = 'abc123def456'
10
+ end
11
+ end
12
+
13
+ def build_notice(args = {})
14
+ configuration = args.delete(:configuration) || configure
15
+ HoptoadNotifier::Notice.new(configuration.merge(args))
16
+ end
17
+
18
+ def stub_request(attrs = {})
19
+ stub('request', { :parameters => { 'one' => 'two' },
20
+ :protocol => 'http',
21
+ :host => 'some.host',
22
+ :request_uri => '/some/uri',
23
+ :session => { :to_hash => { 'a' => 'b' } },
24
+ :env => { 'three' => 'four' } }.update(attrs))
25
+ end
26
+
27
+ should "set the api key" do
28
+ api_key = 'key'
29
+ notice = build_notice(:api_key => api_key)
30
+ assert_equal api_key, notice.api_key
31
+ end
32
+
33
+ should "accept a project root" do
34
+ project_root = '/path/to/project'
35
+ notice = build_notice(:project_root => project_root)
36
+ assert_equal project_root, notice.project_root
37
+ end
38
+
39
+ should "accept a component" do
40
+ assert_equal 'users_controller', build_notice(:component => 'users_controller').controller
41
+ end
42
+
43
+ should "alias the component as controller" do
44
+ assert_equal 'users_controller', build_notice(:controller => 'users_controller').component
45
+ assert_equal 'users_controller', build_notice(:component => 'users_controller').controller
46
+ end
47
+
48
+ should "accept a action" do
49
+ assert_equal 'index', build_notice(:action => 'index').action
50
+ end
51
+
52
+ should "accept a url" do
53
+ url = 'http://some.host/uri'
54
+ notice = build_notice(:url => url)
55
+ assert_equal url, notice.url
56
+ end
57
+
58
+ should "accept a backtrace from an exception or hash" do
59
+ array = ["user.rb:34:in `crazy'"]
60
+ exception = build_exception
61
+ exception.set_backtrace array
62
+ backtrace = HoptoadNotifier::Backtrace.parse(array)
63
+ notice_from_exception = build_notice(:exception => exception)
64
+
65
+
66
+ assert_equal backtrace,
67
+ notice_from_exception.backtrace,
68
+ "backtrace was not correctly set from an exception"
69
+
70
+ notice_from_hash = build_notice(:backtrace => array)
71
+ assert_equal backtrace,
72
+ notice_from_hash.backtrace,
73
+ "backtrace was not correctly set from a hash"
74
+ end
75
+
76
+ should "pass its backtrace filters for parsing" do
77
+ backtrace_array = ['my/file/backtrace:3']
78
+ exception = build_exception
79
+ exception.set_backtrace(backtrace_array)
80
+ HoptoadNotifier::Backtrace.expects(:parse).with(backtrace_array, {:filters => 'foo'})
81
+
82
+ notice = HoptoadNotifier::Notice.new({:exception => exception, :backtrace_filters => 'foo'})
83
+ end
84
+
85
+ should "set the error class from an exception or hash" do
86
+ assert_accepts_exception_attribute :error_class do |exception|
87
+ exception.class.name
88
+ end
89
+ end
90
+
91
+ should "set the error message from an exception or hash" do
92
+ assert_accepts_exception_attribute :error_message do |exception|
93
+ "#{exception.class.name}: #{exception.message}"
94
+ end
95
+ end
96
+
97
+ should "accept parameters from a request or hash" do
98
+ parameters = { 'one' => 'two' }
99
+ notice_from_hash = build_notice(:parameters => parameters)
100
+ assert_equal notice_from_hash.parameters, parameters
101
+ end
102
+
103
+ should "accept session data from a session[:data] hash" do
104
+ data = { 'one' => 'two' }
105
+ notice = build_notice(:session => { :data => data })
106
+ assert_equal data, notice.session_data
107
+ end
108
+
109
+ should "accept session data from a session_data hash" do
110
+ data = { 'one' => 'two' }
111
+ notice = build_notice(:session_data => data)
112
+ assert_equal data, notice.session_data
113
+ end
114
+
115
+ should "accept an environment name" do
116
+ assert_equal 'development', build_notice(:environment_name => 'development').environment_name
117
+ end
118
+
119
+ should "accept CGI data from a hash" do
120
+ data = { 'string' => 'value' }
121
+ notice = build_notice(:cgi_data => data)
122
+ assert_equal data, notice.cgi_data, "should take CGI data from a hash"
123
+ end
124
+
125
+ should "accept notifier information" do
126
+ params = { :notifier_name => 'a name for a notifier',
127
+ :notifier_version => '1.0.5',
128
+ :notifier_url => 'http://notifiers.r.us/download' }
129
+ notice = build_notice(params)
130
+ assert_equal params[:notifier_name], notice.notifier_name
131
+ assert_equal params[:notifier_version], notice.notifier_version
132
+ assert_equal params[:notifier_url], notice.notifier_url
133
+ end
134
+
135
+ should "set sensible defaults without an exception" do
136
+ backtrace = HoptoadNotifier::Backtrace.parse(build_backtrace_array)
137
+ notice = build_notice(:backtrace => build_backtrace_array)
138
+
139
+ assert_equal 'Notification', notice.error_message
140
+ assert_array_starts_with backtrace.lines, notice.backtrace.lines
141
+ assert_equal({}, notice.parameters)
142
+ assert_equal({}, notice.session_data)
143
+ end
144
+
145
+ should "use the caller as the backtrace for an exception without a backtrace" do
146
+ filters = HoptoadNotifier::Configuration.new.backtrace_filters
147
+ backtrace = HoptoadNotifier::Backtrace.parse(caller, :filters => filters)
148
+ notice = build_notice(:exception => StandardError.new('error'), :backtrace => nil)
149
+
150
+ assert_array_starts_with backtrace.lines, notice.backtrace.lines
151
+ end
152
+
153
+ should "convert unserializable objects to strings" do
154
+ assert_serializes_hash(:parameters)
155
+ assert_serializes_hash(:cgi_data)
156
+ assert_serializes_hash(:session_data)
157
+ end
158
+
159
+ should "filter parameters" do
160
+ assert_filters_hash(:parameters)
161
+ end
162
+
163
+ should "filter cgi data" do
164
+ assert_filters_hash(:cgi_data)
165
+ end
166
+
167
+ context "a Notice turned into XML" do
168
+ setup do
169
+ HoptoadNotifier.configure do |config|
170
+ config.api_key = "1234567890"
171
+ end
172
+
173
+ @exception = build_exception
174
+
175
+ @notice = build_notice({
176
+ :notifier_name => 'a name',
177
+ :notifier_version => '0.1.0',
178
+ :notifier_url => 'http://some.url/path',
179
+ :exception => @exception,
180
+ :controller => "controller",
181
+ :action => "action",
182
+ :url => "http://url.com",
183
+ :parameters => { "paramskey" => "paramsvalue",
184
+ "nestparentkey" => { "nestkey" => "nestvalue" } },
185
+ :session_data => { "sessionkey" => "sessionvalue" },
186
+ :cgi_data => { "cgikey" => "cgivalue" },
187
+ :project_root => "RAILS_ROOT",
188
+ :environment_name => "RAILS_ENV"
189
+ })
190
+
191
+ @document = @notice.to_xml
192
+ end
193
+
194
+ should "validate against the XML schema" do
195
+ assert_valid_notice_document @document
196
+ end
197
+
198
+ should "serialize a Notice to XML when sent #to_xml" do
199
+ assert_equal @document['api_key'], @notice.api_key
200
+
201
+ assert_equal @document['version'], @notice.notifier_version
202
+ assert_equal @document['error']['message'], @notice.error_message
203
+ #assert_equal @document['error']['raised_at'], Time.now
204
+ assert_equal @document['error']['backtrace'], @notice.backtrace.lines
205
+
206
+ assert_equal @document['error']['request']['url'], @notice.url
207
+ assert_equal @document['error']['request']['component'], @notice.controller
208
+ assert_equal @document['error']['request']['action'], @notice.action
209
+
210
+ assert_equal @document['error']['environment']['root'], "RAILS_ROOT"
211
+ assert_equal @document['error']['environment']['name'], "RAILS_ENV"
212
+
213
+ assert_equal @document['error']['request']['params'], {"paramskey"=>"paramsvalue", "nestparentkey"=>{"nestkey"=>"nestvalue"}}
214
+ assert_equal @document['error']['session'], { "sessionkey" => "sessionvalue" }
215
+ assert_equal @document['error']['request']['cgi-data'], { "cgikey" => "cgivalue" }
216
+ end
217
+ end
218
+
219
+ should "not send empty request data" do
220
+ notice = build_notice
221
+ assert_nil notice.url
222
+ assert_nil notice.controller
223
+ assert_nil notice.action
224
+
225
+ document = notice.to_xml
226
+ assert !document['error'].key?('request')
227
+
228
+ assert_valid_notice_document document
229
+ end
230
+
231
+ %w(url controller action).each do |var|
232
+ should "send a request if #{var} is present" do
233
+ notice = build_notice(var.to_sym => 'value')
234
+ document = notice.to_xml
235
+ assert document['error'].key?('request')
236
+ end
237
+ end
238
+
239
+ %w(parameters cgi_data session_data).each do |var|
240
+ should "send a request if #{var} is present" do
241
+ notice = build_notice(var.to_sym => { 'key' => 'value' })
242
+ document = notice.to_xml
243
+ assert !document['error']['request'].empty?
244
+ end
245
+ end
246
+
247
+ should "not ignore an exception not matching ignore filters" do
248
+ notice = build_notice(:error_class => 'ArgumentError',
249
+ :ignore => ['Argument'],
250
+ :ignore_by_filters => [lambda { |notice| false }])
251
+ assert !notice.ignore?
252
+ end
253
+
254
+ should "ignore an exception with a matching error class" do
255
+ notice = build_notice(:error_class => 'ArgumentError',
256
+ :ignore => [ArgumentError])
257
+ assert notice.ignore?
258
+ end
259
+
260
+ should "ignore an exception with a matching error class name" do
261
+ notice = build_notice(:error_class => 'ArgumentError',
262
+ :ignore => ['ArgumentError'])
263
+ assert notice.ignore?
264
+ end
265
+
266
+ should "ignore an exception with a matching filter" do
267
+ filter = lambda {|notice| notice.error_class == 'ArgumentError' }
268
+ notice = build_notice(:error_class => 'ArgumentError',
269
+ :ignore_by_filters => [filter])
270
+ assert notice.ignore?
271
+ end
272
+
273
+ should "not raise without an ignore list" do
274
+ notice = build_notice(:ignore => nil, :ignore_by_filters => nil)
275
+ assert_nothing_raised do
276
+ notice.ignore?
277
+ end
278
+ end
279
+
280
+ should "ignore RecordNotFound error by default" do
281
+ notice = build_notice(:error_class => 'ActiveRecord::RecordNotFound')
282
+ assert notice.ignore?
283
+ end
284
+
285
+ should "ignore RoutingError error by default" do
286
+ notice = build_notice(:error_class => 'ActionController::RoutingError')
287
+ assert notice.ignore?
288
+ end
289
+
290
+ should "ignore InvalidAuthenticityToken error by default" do
291
+ notice = build_notice(:error_class => 'ActionController::InvalidAuthenticityToken')
292
+ assert notice.ignore?
293
+ end
294
+
295
+ should "ignore TamperedWithCookie error by default" do
296
+ notice = build_notice(:error_class => 'CGI::Session::CookieStore::TamperedWithCookie')
297
+ assert notice.ignore?
298
+ end
299
+
300
+ should "ignore UnknownAction error by default" do
301
+ notice = build_notice(:error_class => 'ActionController::UnknownAction')
302
+ assert notice.ignore?
303
+ end
304
+
305
+ should "act like a hash" do
306
+ notice = build_notice(:error_message => 'some message')
307
+ assert_equal notice.error_message, notice[:error_message]
308
+ end
309
+
310
+ should "return params on notice[:request][:params]" do
311
+ params = { 'one' => 'two' }
312
+ notice = build_notice(:parameters => params)
313
+ assert_equal params, notice[:request][:params]
314
+ end
315
+
316
+ should "ensure #to_hash is called on objects that support it" do
317
+ assert_nothing_raised do
318
+ build_notice(:session => { :object => stub(:to_hash => {}) })
319
+ end
320
+ end
321
+
322
+ should "extract data from a rack environment hash" do
323
+ # TODO: extract session data
324
+ # TODO: extract controller
325
+ # TODO: extract action
326
+ url = "https://subdomain.happylane.com:100/test/file.rb?var=value&var2=value2"
327
+ parameters = { 'var' => 'value', 'var2' => 'value2' }
328
+ env = Rack::MockRequest.env_for(url)
329
+
330
+ notice = build_notice(:rack_env => env)
331
+
332
+ assert_equal url, notice.url
333
+ assert_equal parameters, notice.parameters
334
+ assert_equal 'GET', notice.cgi_data['REQUEST_METHOD']
335
+ end
336
+
337
+ def assert_accepts_exception_attribute(attribute, args = {}, &block)
338
+ exception = build_exception
339
+ block ||= lambda { exception.send(attribute) }
340
+ value = block.call(exception)
341
+
342
+ notice_from_exception = build_notice(args.merge(:exception => exception))
343
+
344
+ assert_equal notice_from_exception.send(attribute),
345
+ value,
346
+ "#{attribute} was not correctly set from an exception"
347
+
348
+ notice_from_hash = build_notice(args.merge(attribute => value))
349
+ assert_equal notice_from_hash.send(attribute),
350
+ value,
351
+ "#{attribute} was not correctly set from a hash"
352
+ end
353
+
354
+ def assert_serializes_hash(attribute)
355
+ [File.open(__FILE__), Proc.new { puts "boo!" }, Module.new].each do |object|
356
+ hash = {
357
+ :strange_object => object,
358
+ :sub_hash => {
359
+ :sub_object => object
360
+ },
361
+ :array => [object]
362
+ }
363
+ notice = build_notice(attribute => hash)
364
+ hash = notice.send(attribute)
365
+ assert_equal object.to_s, hash[:strange_object], "objects should be serialized"
366
+ assert_kind_of Hash, hash[:sub_hash], "subhashes should be kept"
367
+ assert_equal object.to_s, hash[:sub_hash][:sub_object], "subhash members should be serialized"
368
+ assert_kind_of Array, hash[:array], "arrays should be kept"
369
+ assert_equal object.to_s, hash[:array].first, "array members should be serialized"
370
+ end
371
+ end
372
+
373
+ def assert_valid_notice_document(document)
374
+ assert document.kind_of?(Hash)
375
+ end
376
+
377
+ def assert_filters_hash(attribute)
378
+ filters = %w(abc def)
379
+ original = { 'abc' => "123", 'def' => "456", 'ghi' => "789", 'nested' => { 'abc' => '100' } }
380
+ filtered = { 'abc' => "[FILTERED]",
381
+ 'def' => "[FILTERED]",
382
+ 'ghi' => "789",
383
+ 'nested' => { 'abc' => '[FILTERED]' } }
384
+
385
+ notice = build_notice(:params_filters => filters, attribute => original)
386
+
387
+ assert_equal(filtered,
388
+ notice.send(attribute))
389
+ end
390
+
391
+ def build_backtrace_array
392
+ ["app/models/user.rb:13:in `magic'",
393
+ "app/controllers/users_controller.rb:8:in `index'"]
394
+ end
395
+ end
@@ -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