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.
- data/INSTALL +25 -0
- data/MIT-LICENSE +22 -0
- data/README.rdoc +289 -0
- data/Rakefile +124 -0
- data/SUPPORTED_RAILS_VERSIONS +8 -0
- data/TESTING.rdoc +8 -0
- data/generators/hoptoad/hoptoad_generator.rb +55 -0
- data/generators/hoptoad/lib/insert_commands.rb +34 -0
- data/generators/hoptoad/lib/rake_commands.rb +24 -0
- data/generators/hoptoad/templates/capistrano_hook.rb +6 -0
- data/generators/hoptoad/templates/hoptoad_notifier_tasks.rake +5 -0
- data/generators/hoptoad/templates/initializer.rb +7 -0
- data/lib/hoptoad_notifier/backtrace.rb +99 -0
- data/lib/hoptoad_notifier/capistrano.rb +20 -0
- data/lib/hoptoad_notifier/configuration.rb +232 -0
- data/lib/hoptoad_notifier/notice.rb +287 -0
- data/lib/hoptoad_notifier/rack.rb +40 -0
- data/lib/hoptoad_notifier/rails/action_controller_catcher.rb +29 -0
- data/lib/hoptoad_notifier/rails/controller_methods.rb +59 -0
- data/lib/hoptoad_notifier/rails/error_lookup.rb +33 -0
- data/lib/hoptoad_notifier/rails.rb +37 -0
- data/lib/hoptoad_notifier/sender.rb +85 -0
- data/lib/hoptoad_notifier/tasks.rb +97 -0
- data/lib/hoptoad_notifier/version.rb +3 -0
- data/lib/hoptoad_notifier.rb +146 -0
- data/lib/hoptoad_tasks.rb +37 -0
- data/lib/templates/rescue.erb +91 -0
- data/rails/init.rb +1 -0
- data/script/integration_test.rb +38 -0
- data/test/backtrace_test.rb +118 -0
- data/test/catcher_test.rb +300 -0
- data/test/configuration_test.rb +208 -0
- data/test/helper.rb +232 -0
- data/test/hoptoad_tasks_test.rb +138 -0
- data/test/logger_test.rb +85 -0
- data/test/notice_test.rb +395 -0
- data/test/notifier_test.rb +222 -0
- data/test/rack_test.rb +58 -0
- data/test/rails_initializer_test.rb +36 -0
- data/test/sender_test.rb +123 -0
- metadata +164 -0
data/test/notice_test.rb
ADDED
@@ -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
|