airbrake 3.1.12 → 3.1.13
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +61 -0
- data/README.md +36 -17
- data/Rakefile +14 -8
- data/TESTED_AGAINST +1 -0
- data/airbrake.gemspec +3 -3
- data/features/metal.feature +1 -1
- data/features/rails.feature +1 -0
- data/features/rake.feature +4 -0
- data/features/sinatra.feature +72 -1
- data/features/support/rake/Rakefile +14 -4
- data/generators/airbrake/airbrake_generator.rb +5 -5
- data/lib/airbrake.rb +2 -9
- data/lib/airbrake/backtrace.rb +8 -13
- data/lib/airbrake/capistrano.rb +58 -2
- data/lib/airbrake/cli/runner.rb +1 -0
- data/lib/airbrake/configuration.rb +31 -11
- data/lib/airbrake/notice.rb +52 -61
- data/lib/airbrake/rails/controller_methods.rb +7 -3
- data/lib/airbrake/rails/javascript_notifier.rb +56 -31
- data/lib/airbrake/rake_handler.rb +3 -2
- data/lib/airbrake/response.rb +6 -8
- data/lib/airbrake/sender.rb +1 -1
- data/lib/airbrake/sinatra.rb +9 -2
- data/lib/airbrake/user_informer.rb +1 -1
- data/lib/airbrake/version.rb +1 -1
- data/lib/airbrake_tasks.rb +2 -2
- data/lib/rails/generators/airbrake/airbrake_generator.rb +5 -5
- data/lib/templates/javascript_notifier_configuration +12 -0
- data/lib/templates/javascript_notifier_loader +6 -0
- data/resources/notice.xml +2 -1
- data/test/airbrake_tasks_test.rb +2 -2
- data/test/backtrace_test.rb +19 -0
- data/test/capistrano_test.rb +9 -1
- data/test/configuration_test.rb +49 -2
- data/test/controller_methods_test.rb +22 -0
- data/test/helper.rb +29 -155
- data/test/integration.rb +15 -0
- data/test/{catcher_test.rb → integration/catcher_test.rb} +130 -19
- data/test/{javascript_notifier_test.rb → integration/javascript_notifier_test.rb} +0 -1
- data/test/logger_test.rb +11 -11
- data/test/notice_test.rb +8 -2
- data/test/notifier_test.rb +6 -6
- data/test/sender_test.rb +1 -1
- metadata +34 -31
- data/lib/templates/javascript_notifier +0 -20
data/test/helper.rb
CHANGED
@@ -1,147 +1,39 @@
|
|
1
|
-
|
2
|
-
require 'rubygems'
|
1
|
+
$VERBOSE = ENV["VERBOSE"]
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
require 'mocha'
|
9
|
-
|
10
|
-
require 'abstract_controller'
|
11
|
-
require 'action_controller'
|
12
|
-
require 'action_dispatch'
|
13
|
-
require 'active_support/dependencies'
|
14
|
-
require 'active_model'
|
15
|
-
require 'active_record'
|
16
|
-
require 'active_support/core_ext/kernel/reporting'
|
17
|
-
|
18
|
-
require 'nokogiri'
|
19
|
-
require 'rack'
|
20
|
-
require 'bourne'
|
21
|
-
require 'sham_rack'
|
22
|
-
require 'json-schema'
|
23
|
-
|
24
|
-
require "airbrake"
|
25
|
-
|
26
|
-
require "shoulda-matchers"
|
27
|
-
require "shoulda-context"
|
28
|
-
|
29
|
-
begin require 'redgreen'; rescue LoadError; end
|
30
|
-
|
31
|
-
# Show backtraces for deprecated behavior for quicker cleanup.
|
32
|
-
ActiveSupport::Deprecation.debug = true
|
33
|
-
|
34
|
-
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
|
35
|
-
FIXTURES = Pathname.new(FIXTURE_LOAD_PATH)
|
36
|
-
|
37
|
-
SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
|
38
|
-
|
39
|
-
class RoutedRackApp
|
40
|
-
attr_reader :routes
|
41
|
-
|
42
|
-
def initialize(routes, &blk)
|
43
|
-
@routes = routes
|
44
|
-
@stack = ActionDispatch::MiddlewareStack.new(&blk).build(@routes)
|
3
|
+
module Kernel
|
4
|
+
def silence_warnings
|
5
|
+
with_warnings(nil) { yield }
|
45
6
|
end
|
46
7
|
|
47
|
-
def
|
48
|
-
|
8
|
+
def with_warnings(flag)
|
9
|
+
old_verbose, $VERBOSE = $VERBOSE, flag
|
10
|
+
yield
|
11
|
+
ensure
|
12
|
+
$VERBOSE = old_verbose
|
49
13
|
end
|
50
14
|
end
|
51
15
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
controller_param
|
68
|
-
end
|
69
|
-
|
70
|
-
def dispatch(controller, action, env)
|
71
|
-
[200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]]
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def self.stub_controllers
|
76
|
-
old_dispatcher = ActionDispatch::Routing::RouteSet::Dispatcher
|
77
|
-
ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
|
78
|
-
ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, StubDispatcher }
|
79
|
-
yield ActionDispatch::Routing::RouteSet.new
|
80
|
-
ensure
|
81
|
-
ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
|
82
|
-
ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, old_dispatcher }
|
83
|
-
end
|
84
|
-
|
85
|
-
def with_routing(&block)
|
86
|
-
temporary_routes = ActionDispatch::Routing::RouteSet.new
|
87
|
-
old_app, self.class.app = self.class.app, self.class.build_app(temporary_routes)
|
88
|
-
old_routes = SharedTestRoutes
|
89
|
-
silence_warnings { Object.const_set(:SharedTestRoutes, temporary_routes) }
|
90
|
-
|
91
|
-
yield temporary_routes
|
92
|
-
ensure
|
93
|
-
self.class.app = old_app
|
94
|
-
silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) }
|
95
|
-
end
|
96
|
-
|
97
|
-
def with_autoload_path(path)
|
98
|
-
path = File.join(File.dirname(__FILE__), "fixtures", path)
|
99
|
-
if ActiveSupport::Dependencies.autoload_paths.include?(path)
|
100
|
-
yield
|
101
|
-
else
|
102
|
-
begin
|
103
|
-
ActiveSupport::Dependencies.autoload_paths << path
|
104
|
-
yield
|
105
|
-
ensure
|
106
|
-
ActiveSupport::Dependencies.autoload_paths.reject! {|p| p == path}
|
107
|
-
ActiveSupport::Dependencies.clear
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
|
115
|
-
setup do
|
116
|
-
@routes = SharedTestRoutes
|
117
|
-
end
|
16
|
+
silence_warnings do
|
17
|
+
require 'test/unit'
|
18
|
+
require 'rubygems'
|
19
|
+
|
20
|
+
require 'thread'
|
21
|
+
|
22
|
+
require 'mocha/setup'
|
23
|
+
require 'nokogiri'
|
24
|
+
require 'rack'
|
25
|
+
require 'bourne'
|
26
|
+
require 'sham_rack'
|
27
|
+
require 'json-schema'
|
28
|
+
require "shoulda-matchers"
|
29
|
+
require "shoulda-context"
|
30
|
+
begin require 'redgreen'; rescue LoadError; end
|
118
31
|
end
|
119
32
|
|
33
|
+
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
|
120
34
|
|
121
35
|
|
122
|
-
|
123
|
-
class Base
|
124
|
-
include ActionController::Testing
|
125
|
-
end
|
126
|
-
|
127
|
-
Base.view_paths = FIXTURE_LOAD_PATH
|
128
|
-
|
129
|
-
class TestCase
|
130
|
-
include ActionDispatch::TestProcess
|
131
|
-
|
132
|
-
setup do
|
133
|
-
@routes = SharedTestRoutes
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
# This stub emulates the Railtie including the URL helpers from a Rails application
|
139
|
-
module ActionController
|
140
|
-
class Base
|
141
|
-
include SharedTestRoutes.url_helpers
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
36
|
+
require "airbrake"
|
145
37
|
|
146
38
|
module TestMethods
|
147
39
|
def rescue_action e
|
@@ -287,27 +179,6 @@ module DefinesConstants
|
|
287
179
|
end
|
288
180
|
end
|
289
181
|
|
290
|
-
# Also stolen from AS 2.3.2
|
291
|
-
class Array
|
292
|
-
# Wraps the object in an Array unless it's an Array. Converts the
|
293
|
-
# object to an Array using #to_ary if it implements that.
|
294
|
-
def self.wrap(object)
|
295
|
-
case object
|
296
|
-
when nil
|
297
|
-
[]
|
298
|
-
when self
|
299
|
-
object
|
300
|
-
else
|
301
|
-
if object.respond_to?(:to_ary)
|
302
|
-
object.to_ary
|
303
|
-
else
|
304
|
-
[object]
|
305
|
-
end
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
end
|
310
|
-
|
311
182
|
class CollectingSender
|
312
183
|
attr_reader :collected
|
313
184
|
|
@@ -322,12 +193,15 @@ end
|
|
322
193
|
|
323
194
|
class BacktracedException < Exception
|
324
195
|
attr_accessor :backtrace
|
196
|
+
|
325
197
|
def initialize(opts)
|
326
198
|
@backtrace = opts[:backtrace]
|
327
199
|
end
|
200
|
+
|
328
201
|
def set_backtrace(bt)
|
329
202
|
@backtrace = bt
|
330
203
|
end
|
204
|
+
|
331
205
|
def message
|
332
206
|
"Something went wrong. Did you press the red button?"
|
333
207
|
end
|
data/test/integration.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.expand_path '../helper', __FILE__
|
2
|
+
|
3
|
+
silence_warnings do
|
4
|
+
require 'abstract_controller'
|
5
|
+
require 'action_controller'
|
6
|
+
require 'action_dispatch'
|
7
|
+
require 'active_support/dependencies'
|
8
|
+
require 'active_support/core_ext/kernel/reporting'
|
9
|
+
|
10
|
+
require "erb"
|
11
|
+
require "action_view"
|
12
|
+
end
|
13
|
+
|
14
|
+
require File.expand_path "../integration/javascript_notifier_test", __FILE__
|
15
|
+
require File.expand_path "../integration/catcher_test", __FILE__
|
@@ -1,8 +1,119 @@
|
|
1
|
-
require File.expand_path '../helper', __FILE__
|
2
|
-
|
3
1
|
require 'airbrake/rails/controller_methods'
|
4
2
|
require 'airbrake/rails/middleware'
|
5
3
|
|
4
|
+
unless defined?(ActionDispatch::IntegrationTest) # Rails 3.0
|
5
|
+
# what follows is a dirty hack which makes
|
6
|
+
# AD::IntegrationTest possible in Rails 3.0
|
7
|
+
ActiveSupport::Deprecation.debug = true
|
8
|
+
|
9
|
+
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
|
10
|
+
FIXTURES = Pathname.new(FIXTURE_LOAD_PATH)
|
11
|
+
|
12
|
+
SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
|
13
|
+
|
14
|
+
class RoutedRackApp
|
15
|
+
attr_reader :routes
|
16
|
+
|
17
|
+
def initialize(routes, &blk)
|
18
|
+
@routes = routes
|
19
|
+
@stack = ActionDispatch::MiddlewareStack.new(&blk).build(@routes)
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(env)
|
23
|
+
@stack.call(env)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class ActionController::IntegrationTest < ActiveSupport::TestCase
|
28
|
+
def self.build_app(routes = nil)
|
29
|
+
RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
|
30
|
+
yield(middleware) if block_given?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
self.app = build_app
|
35
|
+
|
36
|
+
# Stub Rails dispatcher so it does not get controller references and
|
37
|
+
# simply return the controller#action as Rack::Body.
|
38
|
+
class StubDispatcher < ::ActionDispatch::Routing::RouteSet::Dispatcher
|
39
|
+
protected
|
40
|
+
def controller_reference(controller_param)
|
41
|
+
controller_param
|
42
|
+
end
|
43
|
+
|
44
|
+
def dispatch(controller, action, env)
|
45
|
+
[200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.stub_controllers
|
50
|
+
old_dispatcher = ActionDispatch::Routing::RouteSet::Dispatcher
|
51
|
+
ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
|
52
|
+
ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, StubDispatcher }
|
53
|
+
yield ActionDispatch::Routing::RouteSet.new
|
54
|
+
ensure
|
55
|
+
ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
|
56
|
+
ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, old_dispatcher }
|
57
|
+
end
|
58
|
+
|
59
|
+
def with_routing(&block)
|
60
|
+
temporary_routes = ActionDispatch::Routing::RouteSet.new
|
61
|
+
old_app, self.class.app = self.class.app, self.class.build_app(temporary_routes)
|
62
|
+
old_routes = SharedTestRoutes
|
63
|
+
silence_warnings { Object.const_set(:SharedTestRoutes, temporary_routes) }
|
64
|
+
|
65
|
+
yield temporary_routes
|
66
|
+
ensure
|
67
|
+
self.class.app = old_app
|
68
|
+
silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) }
|
69
|
+
end
|
70
|
+
|
71
|
+
def with_autoload_path(path)
|
72
|
+
path = File.join(File.dirname(__FILE__), "fixtures", path)
|
73
|
+
if ActiveSupport::Dependencies.autoload_paths.include?(path)
|
74
|
+
yield
|
75
|
+
else
|
76
|
+
begin
|
77
|
+
ActiveSupport::Dependencies.autoload_paths << path
|
78
|
+
yield
|
79
|
+
ensure
|
80
|
+
ActiveSupport::Dependencies.autoload_paths.reject! {|p| p == path}
|
81
|
+
ActiveSupport::Dependencies.clear
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
|
88
|
+
setup do
|
89
|
+
@routes = SharedTestRoutes
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
module ActionController
|
94
|
+
class Base
|
95
|
+
include ActionController::Testing
|
96
|
+
end
|
97
|
+
|
98
|
+
Base.view_paths = FIXTURE_LOAD_PATH
|
99
|
+
|
100
|
+
class TestCase
|
101
|
+
include ActionDispatch::TestProcess
|
102
|
+
|
103
|
+
setup do
|
104
|
+
@routes = SharedTestRoutes
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# This stub emulates the Railtie including the URL helpers from a Rails application
|
110
|
+
module ActionController
|
111
|
+
class Base
|
112
|
+
include SharedTestRoutes.url_helpers
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end # end Rails 3.0 hack
|
116
|
+
|
6
117
|
module ActionDispatch
|
7
118
|
class ShowExceptions
|
8
119
|
private
|
@@ -36,9 +147,9 @@ class ActionControllerCatcherTest < ActionDispatch::IntegrationTest
|
|
36
147
|
def assert_sent_hash(hash, xpath)
|
37
148
|
hash.each do |key, value|
|
38
149
|
next if key.match(/^airbrake\./) || # We added this key.
|
39
|
-
hash[key]
|
150
|
+
hash[key] !~ /\S/
|
40
151
|
|
41
|
-
|
152
|
+
element_xpath = "#{xpath}/var[@key = '#{key}']"
|
42
153
|
if value.respond_to?(:to_hash)
|
43
154
|
assert_sent_hash value.to_hash, element_xpath
|
44
155
|
else
|
@@ -144,13 +255,13 @@ class ActionControllerCatcherTest < ActionDispatch::IntegrationTest
|
|
144
255
|
end
|
145
256
|
|
146
257
|
|
147
|
-
def
|
258
|
+
def test_deliver_notices_from_exceptions_raised_in_public_requests
|
148
259
|
@app = AirbrakeTestController.action(:boom)
|
149
260
|
get '/'
|
150
261
|
assert_caught_and_sent
|
151
262
|
end
|
152
263
|
|
153
|
-
def
|
264
|
+
def test_not_deliver_notices_from_exceptions_in_development_environments
|
154
265
|
Airbrake.configuration.development_environments = ["test"]
|
155
266
|
Airbrake.configuration.environment_name = "test"
|
156
267
|
@app = AirbrakeTestController.action(:boom)
|
@@ -158,28 +269,28 @@ class ActionControllerCatcherTest < ActionDispatch::IntegrationTest
|
|
158
269
|
assert_caught_and_not_sent
|
159
270
|
end
|
160
271
|
|
161
|
-
def
|
272
|
+
def test_not_deliver_notices_from_actions_that_dont_raise
|
162
273
|
@app = AirbrakeTestController.action(:hello)
|
163
274
|
get '/'
|
164
275
|
assert_caught_and_not_sent
|
165
276
|
assert_equal 'hello', response.body
|
166
277
|
end
|
167
278
|
|
168
|
-
def
|
279
|
+
def test_not_deliver_ignored_exceptions_raised_by_actions
|
169
280
|
@app = AirbrakeTestController.action(:boom)
|
170
281
|
ignore(RuntimeError)
|
171
282
|
get '/'
|
172
283
|
assert_caught_and_not_sent
|
173
284
|
end
|
174
285
|
|
175
|
-
def
|
286
|
+
def test_deliver_ignored_exception_raised_manually
|
176
287
|
@app = AirbrakeTestController.action(:manual_airbrake)
|
177
288
|
ignore(RuntimeError)
|
178
289
|
get '/'
|
179
290
|
assert_caught_and_sent
|
180
291
|
end
|
181
292
|
|
182
|
-
def
|
293
|
+
def test_not_deliver_manually_sent_notices_in_local_requests
|
183
294
|
AirbrakeTestController.local = true
|
184
295
|
@app = AirbrakeTestController.action(:manual_airbrake)
|
185
296
|
get '/'
|
@@ -187,62 +298,62 @@ class ActionControllerCatcherTest < ActionDispatch::IntegrationTest
|
|
187
298
|
AirbrakeTestController.local = false
|
188
299
|
end
|
189
300
|
|
190
|
-
def
|
301
|
+
def test_not_create_actions_from_airbrake_methods
|
191
302
|
Airbrake::Rails::ControllerMethods.instance_methods.each do |method|
|
192
303
|
assert !(AirbrakeTestController.new.action_methods.include?(method))
|
193
304
|
end
|
194
305
|
end
|
195
306
|
|
196
|
-
def
|
307
|
+
def test_ignore_exceptions_when_user_agent_is_being_ignored_by_regular_expression
|
197
308
|
Airbrake.configuration.ignore_user_agent_only = [/Ignored/]
|
198
309
|
@app = AirbrakeTestController.action(:boom)
|
199
310
|
get "/", {}, {"HTTP_USER_AGENT" => "ShouldBeIgnored"}
|
200
311
|
assert_caught_and_not_sent
|
201
312
|
end
|
202
313
|
|
203
|
-
def
|
314
|
+
def test_ignore_exceptions_when_user_agent_is_being_ignored_by_string
|
204
315
|
Airbrake.configuration.ignore_user_agent_only = ['IgnoredUserAgent']
|
205
316
|
@app = AirbrakeTestController.action(:boom)
|
206
317
|
get "/", {}, {"HTTP_USER_AGENT" => "IgnoredUserAgent"}
|
207
318
|
assert_caught_and_not_sent
|
208
319
|
end
|
209
320
|
|
210
|
-
def
|
321
|
+
def test_not_ignore_exceptions_when_user_agent_is_not_being_ignored
|
211
322
|
Airbrake.configuration.ignore_user_agent_only = ['IgnoredUserAgent']
|
212
323
|
@app = AirbrakeTestController.action(:boom)
|
213
324
|
get "/", {}, {"HTTP_USER_AGENT" => "NonIgnoredAgent"}
|
214
325
|
assert_caught_and_sent
|
215
326
|
end
|
216
327
|
|
217
|
-
def
|
328
|
+
def test_send_session_data_for_manual_notifications
|
218
329
|
@app = AirbrakeTestController.action(:manual_airbrake)
|
219
330
|
data = { 'one' => 'two' }
|
220
331
|
get "/", :session => data
|
221
332
|
assert_sent_hash data, "/notice/request/session"
|
222
333
|
end
|
223
334
|
|
224
|
-
def
|
335
|
+
def test_send_request_data_for_manual_notification
|
225
336
|
params = { 'controller' => "airbrake_test", 'action' => "index" }
|
226
337
|
@app = AirbrakeTestController.action(:manual_airbrake)
|
227
338
|
get "/", params
|
228
339
|
assert_sent_request_info_for @request
|
229
340
|
end
|
230
341
|
|
231
|
-
def
|
342
|
+
def test_send_request_data_for_manual_notification_with_non_standard_port
|
232
343
|
params = { 'controller' => "airbrake_test", 'action' => "index" }
|
233
344
|
@app = AirbrakeTestController.action(:manual_airbrake)
|
234
345
|
get "/", params, {"SERVER_PORT" => 81}
|
235
346
|
assert_sent_request_info_for @request
|
236
347
|
end
|
237
348
|
|
238
|
-
def
|
349
|
+
def test_send_request_data_for_automatic_notification
|
239
350
|
params = { 'controller' => "airbrake_test", 'action' => "index" }
|
240
351
|
@app = AirbrakeTestController.action(:boom)
|
241
352
|
get "/", params
|
242
353
|
assert_sent_request_info_for @request
|
243
354
|
end
|
244
355
|
|
245
|
-
def
|
356
|
+
def test_send_request_data_for_automatic_notification_with_non_standard_port
|
246
357
|
params = { 'controller' => "airbrake_test", 'action' => "index" }
|
247
358
|
@app = AirbrakeTestController.action(:boom)
|
248
359
|
get "/", params, {"SERVER_PORT" => 81}
|