airbrakeV4rails5 4.3.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 (98) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +1716 -0
  3. data/Gemfile +3 -0
  4. data/Guardfile +6 -0
  5. data/INSTALL +20 -0
  6. data/LICENSE +61 -0
  7. data/README.md +148 -0
  8. data/README_FOR_HEROKU_ADDON.md +102 -0
  9. data/Rakefile +179 -0
  10. data/TESTED_AGAINST +7 -0
  11. data/airbrake.gemspec +41 -0
  12. data/bin/airbrake +12 -0
  13. data/features/metal.feature +34 -0
  14. data/features/rack.feature +60 -0
  15. data/features/rails.feature +324 -0
  16. data/features/rake.feature +33 -0
  17. data/features/sinatra.feature +126 -0
  18. data/features/step_definitions/file_steps.rb +14 -0
  19. data/features/step_definitions/rack_steps.rb +27 -0
  20. data/features/step_definitions/rails_application_steps.rb +267 -0
  21. data/features/step_definitions/rake_steps.rb +22 -0
  22. data/features/support/airbrake_shim.rb.template +11 -0
  23. data/features/support/aruba.rb +5 -0
  24. data/features/support/env.rb +39 -0
  25. data/features/support/matchers.rb +35 -0
  26. data/features/support/rails.rb +156 -0
  27. data/features/support/rake/Rakefile +77 -0
  28. data/features/user_informer.feature +57 -0
  29. data/generators/airbrake/airbrake_generator.rb +94 -0
  30. data/generators/airbrake/lib/insert_commands.rb +34 -0
  31. data/generators/airbrake/lib/rake_commands.rb +24 -0
  32. data/generators/airbrake/templates/airbrake_tasks.rake +25 -0
  33. data/generators/airbrake/templates/capistrano_hook.rb +6 -0
  34. data/generators/airbrake/templates/initializer.rb +4 -0
  35. data/install.rb +1 -0
  36. data/lib/airbrake.rb +191 -0
  37. data/lib/airbrake/backtrace.rb +103 -0
  38. data/lib/airbrake/capistrano.rb +103 -0
  39. data/lib/airbrake/capistrano3.rb +3 -0
  40. data/lib/airbrake/cli/client.rb +76 -0
  41. data/lib/airbrake/cli/options.rb +45 -0
  42. data/lib/airbrake/cli/printer.rb +33 -0
  43. data/lib/airbrake/cli/project.rb +17 -0
  44. data/lib/airbrake/cli/project_factory.rb +33 -0
  45. data/lib/airbrake/cli/runner.rb +49 -0
  46. data/lib/airbrake/cli/validator.rb +8 -0
  47. data/lib/airbrake/configuration.rb +366 -0
  48. data/lib/airbrake/jobs/send_job.rb +7 -0
  49. data/lib/airbrake/notice.rb +411 -0
  50. data/lib/airbrake/rack.rb +64 -0
  51. data/lib/airbrake/rails.rb +45 -0
  52. data/lib/airbrake/rails/action_controller_catcher.rb +32 -0
  53. data/lib/airbrake/rails/controller_methods.rb +146 -0
  54. data/lib/airbrake/rails/error_lookup.rb +35 -0
  55. data/lib/airbrake/rails/middleware.rb +63 -0
  56. data/lib/airbrake/rails3_tasks.rb +126 -0
  57. data/lib/airbrake/railtie.rb +44 -0
  58. data/lib/airbrake/rake_handler.rb +75 -0
  59. data/lib/airbrake/response.rb +29 -0
  60. data/lib/airbrake/sender.rb +213 -0
  61. data/lib/airbrake/shared_tasks.rb +59 -0
  62. data/lib/airbrake/sidekiq.rb +8 -0
  63. data/lib/airbrake/sinatra.rb +40 -0
  64. data/lib/airbrake/tasks.rb +81 -0
  65. data/lib/airbrake/tasks/airbrake.cap +28 -0
  66. data/lib/airbrake/user_informer.rb +36 -0
  67. data/lib/airbrake/utils/params_cleaner.rb +141 -0
  68. data/lib/airbrake/utils/rack_filters.rb +45 -0
  69. data/lib/airbrake/version.rb +3 -0
  70. data/lib/airbrake_tasks.rb +62 -0
  71. data/lib/rails/generators/airbrake/airbrake_generator.rb +155 -0
  72. data/lib/templates/rescue.erb +91 -0
  73. data/rails/init.rb +1 -0
  74. data/resources/README.md +34 -0
  75. data/resources/airbrake_2_4.xsd +89 -0
  76. data/resources/airbrake_3_0.json +52 -0
  77. data/resources/ca-bundle.crt +3376 -0
  78. data/script/integration_test.rb +35 -0
  79. data/test/airbrake_tasks_test.rb +161 -0
  80. data/test/backtrace_test.rb +215 -0
  81. data/test/capistrano_test.rb +44 -0
  82. data/test/configuration_test.rb +303 -0
  83. data/test/controller_methods_test.rb +230 -0
  84. data/test/helper.rb +233 -0
  85. data/test/integration.rb +13 -0
  86. data/test/integration/catcher_test.rb +371 -0
  87. data/test/logger_test.rb +79 -0
  88. data/test/notice_test.rb +494 -0
  89. data/test/notifier_test.rb +288 -0
  90. data/test/params_cleaner_test.rb +204 -0
  91. data/test/rack_test.rb +62 -0
  92. data/test/rails_initializer_test.rb +36 -0
  93. data/test/recursion_test.rb +10 -0
  94. data/test/response_test.rb +18 -0
  95. data/test/sender_test.rb +335 -0
  96. data/test/support/response_shim.xml +4 -0
  97. data/test/user_informer_test.rb +29 -0
  98. metadata +469 -0
@@ -0,0 +1,62 @@
1
+ require File.expand_path '../helper', __FILE__
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 = Airbrake::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
+ Airbrake.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 = Airbrake::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(Airbrake, :notify_or_ignore) do |expect|
34
+ expect.with(exception, :rack_env => environment)
35
+ end
36
+ end
37
+
38
+ %w(rack.exception sinatra.error).each do |ex|
39
+
40
+ should "deliver an exception in #{ex}" do
41
+ Airbrake.stubs(:notify_or_ignore)
42
+ exception = build_exception
43
+ environment = { 'key' => 'value' }
44
+
45
+ response = [200, {}, ['okay']]
46
+ app = lambda do |env|
47
+ env[ex] = exception
48
+ response
49
+ end
50
+ stack = Airbrake::Rack.new(app)
51
+
52
+ actual_response = stack.call(environment)
53
+
54
+ assert_equal response, actual_response
55
+ assert_received(Airbrake, :notify_or_ignore) do |expect|
56
+ expect.with(exception, :rack_env => environment)
57
+ end
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ require 'airbrake/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
+ Airbrake::Rails.initialize
16
+ assert_equal "RAILS LOGGER", Airbrake.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
+ Airbrake::Rails.initialize
23
+ assert_equal "RAILS DEFAULT LOGGER", Airbrake.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
+ Airbrake::Rails.initialize
29
+
30
+ Airbrake.configure(true) do |config|
31
+ config.logger = "OVERRIDDEN LOGGER"
32
+ end
33
+
34
+ assert_equal "OVERRIDDEN LOGGER", Airbrake.logger
35
+ end
36
+ end
@@ -0,0 +1,10 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ class RecursionTest < Test::Unit::TestCase
4
+ should "not allow infinite recursion" do
5
+ hash = {:a => :a}
6
+ hash[:hash] = hash
7
+ notice = Airbrake::Notice.new(:parameters => hash)
8
+ assert_equal "[possible infinite recursion halted]", notice.parameters[:hash]
9
+ end
10
+ end
@@ -0,0 +1,18 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ class ResponseTest < Test::Unit::TestCase
4
+ include DefinesConstants
5
+
6
+ def response_body
7
+ File.read File.expand_path('../support/response_shim.xml', __FILE__)
8
+ end
9
+
10
+ should "output a nicely formatted notice details" do
11
+ output = Airbrake::Response.pretty_format(response_body)
12
+
13
+ assert %r{ID: b6817316-9c45-ed26-45eb-780dbb86aadb}, "#{output}"
14
+ assert %r{URL: http://airbrake.io/locate/b6817316-9c45-ed26-45eb-780dbb86aadb},
15
+ "#{output}"
16
+
17
+ end
18
+ end
@@ -0,0 +1,335 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ class SenderTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ reset_config
7
+ end
8
+
9
+ def build_sender(opts = {})
10
+ Airbrake.configure do |conf|
11
+ opts.each {|opt, value| conf.send(:"#{opt}=", value) }
12
+ end
13
+ end
14
+
15
+ def send_exception(args = {})
16
+ notice = args.delete(:notice) || build_notice_data
17
+ notice.stubs(:to_xml)
18
+ sender = args.delete(:sender) || build_sender(args)
19
+ sender.send_to_airbrake(notice)
20
+ end
21
+
22
+ def stub_http(options = {})
23
+ response = stub(:body => options[:body] || 'body')
24
+ http = stub(:post => response,
25
+ :read_timeout= => nil,
26
+ :open_timeout= => nil,
27
+ :ca_file= => nil,
28
+ :verify_mode= => nil,
29
+ :use_ssl= => nil)
30
+ Net::HTTP.stubs(:new => http)
31
+ http
32
+ end
33
+
34
+ should "post to Airbrake when using an HTTP proxy" do
35
+ response = stub(:body => 'body')
36
+ http = stub(:post => response,
37
+ :read_timeout= => nil,
38
+ :open_timeout= => nil,
39
+ :use_ssl= => nil)
40
+ proxy = stub(:new => http)
41
+ Net::HTTP.stubs(:Proxy => proxy)
42
+
43
+ url = "http://api.airbrake.io:80#{Airbrake::Sender::NOTICES_URI}"
44
+ uri = URI.parse(url)
45
+
46
+ proxy_host = 'some.host'
47
+ proxy_port = 88
48
+ proxy_user = 'login'
49
+ proxy_pass = 'passwd'
50
+
51
+ send_exception(:proxy_host => proxy_host,
52
+ :proxy_port => proxy_port,
53
+ :proxy_user => proxy_user,
54
+ :proxy_pass => proxy_pass)
55
+ assert_received(http, :post) do |expect|
56
+ expect.with(uri.path, anything, Airbrake::Sender::HEADERS[:xml])
57
+ end
58
+ assert_received(Net::HTTP, :Proxy) do |expect|
59
+ expect.with(proxy_host, proxy_port, proxy_user, proxy_pass)
60
+ end
61
+ end
62
+
63
+ should "return the created group's id on successful posting" do
64
+ stub_http(:body => '<id type="integer">3799307</id>')
65
+ assert_equal "3799307", send_exception(:secure => false)
66
+ end
67
+
68
+ context "when using the XML API" do
69
+
70
+ should "post to Airbrake with XML passed" do
71
+ xml_notice = Airbrake::Notice.new(:error_class => "FooBar", :error_message => "Foo Bar").to_xml
72
+
73
+ http = stub_http
74
+
75
+ sender = build_sender
76
+ sender.send_to_airbrake(xml_notice)
77
+
78
+ assert_received(http, :post) do |expect|
79
+ expect.with(anything, xml_notice, Airbrake::Sender::HEADERS[:xml])
80
+ end
81
+ end
82
+
83
+ should "post to Airbrake with a Notice instance passed" do
84
+ notice = Airbrake::Notice.new(:error_class => "FooBar", :error_message => "Foo Bar")
85
+
86
+ http = stub_http
87
+
88
+ sender = build_sender
89
+ sender.send_to_airbrake(notice)
90
+
91
+ assert_received(http, :post) do |expect|
92
+ expect.with(anything, notice.to_xml, Airbrake::Sender::HEADERS[:xml])
93
+ end
94
+ end
95
+
96
+ end
97
+
98
+ context "when using new JSON API" do
99
+ should "post to Airbrake with JSON passed" do
100
+ json_notice = Airbrake::Notice.new(:error_class => "FooBar", :error_message => "Foo Bar").to_json
101
+
102
+ http = stub_http
103
+
104
+ sender = build_sender(:project_id => "PROJECT_ID", :host => "collect.airbrake.io")
105
+ sender.send_to_airbrake(json_notice)
106
+
107
+ assert_received(http, :post) do |expect|
108
+ expect.with(anything, json_notice, Airbrake::Sender::HEADERS[:json])
109
+ end
110
+ end
111
+
112
+ should "post to Airbrake keeping the apiKey in the URL" do
113
+ json_notice = Airbrake::Notice.new(:error_class => "FooBar", :error_message => "Foo Bar").to_json
114
+
115
+ http = stub_http
116
+
117
+ sender = build_sender(:project_id => "PROJECT_ID", :host => "collect.airbrake.io")
118
+ sender.send_to_airbrake(json_notice)
119
+
120
+ expected_url = format("%s/PROJECT_ID/notices?key=%s",
121
+ Airbrake::Sender::JSON_API_URI,
122
+ Airbrake.configuration[:api_key])
123
+
124
+ assert_received(http, :post) do |expect|
125
+ expect.with(expected_url, json_notice, Airbrake::Sender::HEADERS[:json])
126
+ end
127
+ end
128
+
129
+ should "post to Airbrake with notice passed" do
130
+ notice = Airbrake::Notice.new(:error_class => "FooBar", :error_message => "Foo Bar")
131
+
132
+ http = stub_http
133
+
134
+ sender = build_sender(:project_id => "PROJECT_ID", :host => "collect.airbrake.io")
135
+ sender.send_to_airbrake(notice)
136
+
137
+ assert_received(http, :post) do |expect|
138
+ expect.with(anything, notice.to_json, Airbrake::Sender::HEADERS[:json])
139
+ end
140
+
141
+ end
142
+ end
143
+
144
+ context "when encountering exceptions: " do
145
+ context "HTTP connection setup problems" do
146
+ should "not be rescued" do
147
+ proxy = stub()
148
+ proxy.stubs(:new).raises(NoMemoryError)
149
+ Net::HTTP.stubs(:Proxy => proxy)
150
+
151
+ assert_raise NoMemoryError do
152
+ build_sender.send(:setup_http_connection)
153
+ end
154
+ end
155
+
156
+ should "be logged" do
157
+ proxy = stub()
158
+ proxy.stubs(:new).raises(RuntimeError)
159
+ Net::HTTP.stubs(:Proxy => proxy)
160
+
161
+ sender = build_sender
162
+ sender.expects(:log)
163
+
164
+ assert_raise RuntimeError do
165
+ sender.send(:setup_http_connection)
166
+ end
167
+
168
+ end
169
+ end
170
+
171
+ context "unexpected exception sending problems" do
172
+ should "be logged" do
173
+ sender = build_sender
174
+ sender.stubs(:setup_http_connection).raises(RuntimeError.new)
175
+
176
+ sender.expects(:log)
177
+ send_exception(:sender => sender)
178
+ end
179
+
180
+ should "return nil no matter what" do
181
+ sender = build_sender
182
+ sender.stubs(:setup_http_connection).raises(LocalJumpError)
183
+
184
+ assert_nothing_thrown do
185
+ assert_nil sender.send_to_airbrake(build_notice_data)
186
+ end
187
+ end
188
+ end
189
+
190
+ should "return nil on failed posting" do
191
+ http = stub_http
192
+ http.stubs(:post).raises(Errno::ECONNREFUSED)
193
+ assert_equal nil, send_exception(:secure => false)
194
+ end
195
+
196
+ should "not fail when posting and a timeout exception occurs" do
197
+ http = stub_http
198
+ http.stubs(:post).raises(TimeoutError)
199
+ assert_nothing_thrown do
200
+ send_exception(:secure => false)
201
+ end
202
+ end
203
+
204
+ should "not fail when posting and a connection refused exception occurs" do
205
+ http = stub_http
206
+ http.stubs(:post).raises(Errno::ECONNREFUSED)
207
+ assert_nothing_thrown do
208
+ send_exception(:secure => false)
209
+ end
210
+ end
211
+
212
+ should "not fail when posting any http exception occurs" do
213
+ http = stub_http
214
+ Airbrake::Sender::HTTP_ERRORS.each do |error|
215
+ http.stubs(:post).raises(error)
216
+ assert_nothing_thrown do
217
+ send_exception(:secure => false)
218
+ end
219
+ end
220
+ end
221
+ end
222
+
223
+ context "SSL" do
224
+ should "post to the right url for non-ssl" do
225
+ http = stub_http
226
+ url = "http://api.airbrake.io:80#{Airbrake::Sender::NOTICES_URI}"
227
+ uri = URI.parse(url)
228
+ send_exception(:secure => false)
229
+ assert_received(http, :post) {|expect| expect.with(uri.path, anything, Airbrake::Sender::HEADERS[:xml]) }
230
+ end
231
+
232
+ should "post to the right path for ssl" do
233
+ http = stub_http
234
+ send_exception(:secure => true)
235
+ assert_received(http, :post) {|expect| expect.with(Airbrake::Sender::NOTICES_URI, anything, Airbrake::Sender::HEADERS[:xml]) }
236
+ end
237
+
238
+ should "verify the SSL peer when the use_ssl option is set to true" do
239
+ url = "https://api.airbrake.io#{Airbrake::Sender::NOTICES_URI}"
240
+ uri = URI.parse(url)
241
+
242
+ real_http = Net::HTTP.new(uri.host, uri.port)
243
+ real_http.stubs(:post => nil)
244
+ proxy = stub(:new => real_http)
245
+ Net::HTTP.stubs(:Proxy => proxy)
246
+ File.stubs(:exist?).with(OpenSSL::X509::DEFAULT_CERT_FILE).returns(false)
247
+
248
+ send_exception(:secure => true)
249
+ assert(real_http.use_ssl?)
250
+ assert_equal(OpenSSL::SSL::VERIFY_PEER, real_http.verify_mode)
251
+ assert_equal(Airbrake.configuration.local_cert_path, real_http.ca_file)
252
+ end
253
+
254
+ should "use the default DEFAULT_CERT_FILE if asked to" do
255
+ config = Airbrake::Configuration.new
256
+ config.use_system_ssl_cert_chain = true
257
+ sender = Airbrake::Sender.new(config)
258
+
259
+ assert(sender.use_system_ssl_cert_chain?)
260
+
261
+ http = sender.send(:setup_http_connection)
262
+ assert_not_equal http.ca_file, config.local_cert_path
263
+ end
264
+
265
+ should "verify the connection when the use_ssl option is set (VERIFY_PEER)" do
266
+ sender = build_sender(:secure => true)
267
+ http = sender.send(:setup_http_connection)
268
+ assert_equal(OpenSSL::SSL::VERIFY_PEER, http.verify_mode)
269
+ end
270
+
271
+ should "use the default cert (OpenSSL::X509::DEFAULT_CERT_FILE) only if explicitly told to" do
272
+ sender = build_sender(:secure => true)
273
+ http = sender.send(:setup_http_connection)
274
+
275
+ assert_equal(Airbrake.configuration.local_cert_path, http.ca_file)
276
+
277
+ File.stubs(:exist?).with(OpenSSL::X509::DEFAULT_CERT_FILE).returns(true)
278
+ sender = build_sender(:secure => true, :use_system_ssl_cert_chain => true)
279
+ http = sender.send(:setup_http_connection)
280
+
281
+ assert_not_equal(Airbrake.configuration.local_cert_path, http.ca_file)
282
+ assert_equal(OpenSSL::X509::DEFAULT_CERT_FILE, http.ca_file)
283
+ end
284
+
285
+ should "connect to the right port for ssl" do
286
+ stub_http
287
+ send_exception(:secure => true)
288
+ assert_received(Net::HTTP, :new) {|expect| expect.with("api.airbrake.io", 443) }
289
+ end
290
+
291
+ should "connect to the right port for non-ssl" do
292
+ stub_http
293
+ send_exception(:secure => false)
294
+ assert_received(Net::HTTP, :new) {|expect| expect.with("api.airbrake.io", 80) }
295
+ end
296
+
297
+ should "use ssl if secure" do
298
+ stub_http
299
+ send_exception(:secure => true, :host => 'example.org')
300
+ assert_received(Net::HTTP, :new) {|expect| expect.with('example.org', 443) }
301
+ end
302
+
303
+ should "not use ssl if not secure" do
304
+ stub_http
305
+ send_exception(:secure => false, :host => 'example.org')
306
+ assert_received(Net::HTTP, :new) {|expect| expect.with('example.org', 80) }
307
+ end
308
+ end
309
+
310
+ context "network timeouts" do
311
+ should "default the open timeout to 2 seconds" do
312
+ http = stub_http
313
+ send_exception
314
+ assert_received(http, :open_timeout=) {|expect| expect.with(2) }
315
+ end
316
+
317
+ should "default the read timeout to 5 seconds" do
318
+ http = stub_http
319
+ send_exception
320
+ assert_received(http, :read_timeout=) {|expect| expect.with(5) }
321
+ end
322
+
323
+ should "allow override of the open timeout" do
324
+ http = stub_http
325
+ send_exception(:http_open_timeout => 4)
326
+ assert_received(http, :open_timeout=) {|expect| expect.with(4) }
327
+ end
328
+
329
+ should "allow override of the read timeout" do
330
+ http = stub_http
331
+ send_exception(:http_read_timeout => 10)
332
+ assert_received(http, :read_timeout=) {|expect| expect.with(10) }
333
+ end
334
+ end
335
+ end