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,35 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'logger'
4
+ require 'fileutils'
5
+
6
+ RAILS_ENV = "production"
7
+ RAILS_ROOT = FileUtils.pwd
8
+ RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
9
+
10
+ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
11
+ require 'airbrake'
12
+
13
+ fail "Please supply an API Key as the first argument" if ARGV.empty?
14
+
15
+ host = ARGV[1] || "api.airbrake.io"
16
+ port = ARGV[2] || 80
17
+ secure = (ARGV[3] == "secure")
18
+ exception = RuntimeError.new "Testing airbrake notifier with secure = #{secure}. If you can see this, it works."
19
+
20
+ Airbrake.configure do |config|
21
+ config.secure = secure
22
+ config.host = host
23
+ config.port = port
24
+ config.api_key = ARGV.first
25
+ end
26
+
27
+ puts "Configuration:"
28
+ Airbrake.configuration.to_hash.each do |key, value|
29
+ puts sprintf("%25s: %s", key.to_s, value.inspect.slice(0, 55))
30
+ end
31
+
32
+ puts "Sending #{secure ? "" : "in"}secure notification to project with key #{ARGV.first}"
33
+ if Airbrake.notify(exception) then puts "\nIntegration test passed with success!"
34
+ else puts "\nIntegration test was unsuccessful."
35
+ end
@@ -0,0 +1,161 @@
1
+ require File.expand_path '../helper', __FILE__
2
+ require 'rubygems'
3
+
4
+ require File.dirname(__FILE__) + '/../lib/airbrake_tasks'
5
+
6
+ class AirbrakeTasksTest < Test::Unit::TestCase
7
+ def successful_response(body = "")
8
+ response = Net::HTTPSuccess.new('1.2', '200', 'OK')
9
+ response.stubs(:body).returns(body)
10
+ return response
11
+ end
12
+
13
+ def unsuccessful_response(body = "")
14
+ response = Net::HTTPClientError.new('1.2', '200', 'OK')
15
+ response.stubs(:body).returns(body)
16
+ return response
17
+ end
18
+
19
+ context "being quiet" do
20
+ setup { AirbrakeTasks.stubs(:puts) }
21
+
22
+ context "in a configured project" do
23
+ setup { Airbrake.configure { |config| config.api_key = "1234123412341234" } }
24
+
25
+ context "on deploy({})" do
26
+ setup { @output = AirbrakeTasks.deploy({}) }
27
+
28
+ before_should "complain about missing rails env" do
29
+ AirbrakeTasks.expects(:puts).with(regexp_matches(/rails environment/i))
30
+ end
31
+
32
+ should "return false" do
33
+ assert !@output
34
+ end
35
+ end
36
+
37
+ context "given an optional HTTP proxy and valid options" do
38
+ setup do
39
+ @response = stub("response", :body => "stub body")
40
+ @http_proxy = stub("proxy", :request => @response)
41
+ @http_proxy_class = stub("proxy_class", :new => @http_proxy)
42
+ @post = stub("post", :set_form_data => nil)
43
+
44
+ Net::HTTP.expects(:Proxy).
45
+ with(Airbrake.configuration.proxy_host,
46
+ Airbrake.configuration.proxy_port,
47
+ Airbrake.configuration.proxy_user,
48
+ Airbrake.configuration.proxy_pass).
49
+ returns(@http_proxy_class)
50
+ Net::HTTP::Post.expects(:new).with("/deploys.txt").returns(@post)
51
+
52
+ @options = { :rails_env => "staging", :dry_run => false }
53
+ end
54
+
55
+ context "performing a dry run" do
56
+ setup { @output = AirbrakeTasks.deploy(@options.merge(:dry_run => true)) }
57
+
58
+ should "return true without performing any actual request" do
59
+ assert_equal true, @output
60
+ assert_received(@http_proxy, :request) do |expects|
61
+ expects.never
62
+ end
63
+ end
64
+ end
65
+
66
+ context "on deploy(options)" do
67
+ setup do
68
+ @output = AirbrakeTasks.deploy(@options)
69
+ end
70
+
71
+ before_should "post to http://api.airbrake.io:80/deploys.txt" do
72
+ @http_proxy_class.expects(:new).with("api.airbrake.io", 80).returns(@http_proxy)
73
+ @post.expects(:set_form_data).with(kind_of(Hash))
74
+ @http_proxy.expects(:request).with(any_parameters).returns(successful_response)
75
+ end
76
+
77
+ before_should "use the project api key" do
78
+ @post.expects(:set_form_data).
79
+ with(has_entries('api_key' => "1234123412341234"))
80
+ end
81
+
82
+ before_should "use send the rails_env param" do
83
+ @post.expects(:set_form_data).
84
+ with(has_entries("deploy[rails_env]" => "staging"))
85
+ end
86
+
87
+ [:local_username, :scm_repository, :scm_revision].each do |key|
88
+ before_should "use send the #{key} param if it's passed in." do
89
+ @options[key] = "value"
90
+ @post.expects(:set_form_data).
91
+ with(has_entries("deploy[#{key}]" => "value"))
92
+ end
93
+ end
94
+
95
+ before_should "puts the response body on success" do
96
+ AirbrakeTasks.expects(:puts).with("body")
97
+ @http_proxy.expects(:request).with(any_parameters).returns(successful_response('body'))
98
+ end
99
+
100
+ before_should "puts the response body on failure" do
101
+ AirbrakeTasks.expects(:puts).with("body")
102
+ @http_proxy.expects(:request).with(any_parameters).returns(unsuccessful_response('body'))
103
+ end
104
+
105
+ should "return false on failure", :before => lambda {
106
+ @http_proxy.expects(:request).with(any_parameters).returns(unsuccessful_response('body'))
107
+ } do
108
+ assert !@output
109
+ end
110
+
111
+ should "return true on success", :before => lambda {
112
+ @http_proxy.expects(:request).with(any_parameters).returns(successful_response('body'))
113
+ } do
114
+ assert @output
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ context "in a configured project with custom host" do
121
+ setup do
122
+ Airbrake.configure do |config|
123
+ config.api_key = "1234123412341234"
124
+ config.host = "custom.host"
125
+ end
126
+ end
127
+
128
+ context "on deploy(:rails_env => 'staging')" do
129
+ setup { @output = AirbrakeTasks.deploy(:rails_env => "staging") }
130
+
131
+ before_should "post to the custom host" do
132
+ @post = stub("post", :set_form_data => nil)
133
+ @http_proxy = stub("proxy", :request => stub("response", :body => "stub body"))
134
+
135
+ @http_proxy_class = stub("proxy_class", :new => @http_proxy)
136
+ @http_proxy_class.expects(:new).with("custom.host", 80).returns(@http_proxy)
137
+ Net::HTTP.expects(:Proxy).with(any_parameters).returns(@http_proxy_class)
138
+ Net::HTTP::Post.expects(:new).with("/deploys.txt").returns(@post)
139
+ @post.expects(:set_form_data).with(kind_of(Hash))
140
+ @http_proxy.expects(:request).with(any_parameters).returns(successful_response)
141
+ end
142
+ end
143
+ end
144
+
145
+ context "when not configured" do
146
+ setup { Airbrake.configure { |config| config.api_key = "" } }
147
+
148
+ context "on deploy(:rails_env => 'staging')" do
149
+ setup { @output = AirbrakeTasks.deploy(:rails_env => "staging") }
150
+
151
+ before_should "complain about missing api key" do
152
+ AirbrakeTasks.expects(:puts).with(regexp_matches(/api key/i))
153
+ end
154
+
155
+ should "return false" do
156
+ assert !@output
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,215 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ class BacktraceTest < Test::Unit::TestCase
4
+
5
+ should "parse a backtrace into lines" do
6
+ array = [
7
+ "app/models/user.rb:13:in `magic'",
8
+ "app/controllers/users_controller.rb:8:in `index'"
9
+ ]
10
+
11
+ backtrace = Airbrake::Backtrace.parse(array)
12
+
13
+ line = backtrace.lines.first
14
+ assert_equal '13', line.number
15
+ assert_equal 'app/models/user.rb', line.file
16
+ assert_equal 'magic', line.method_name
17
+
18
+ line = backtrace.lines.last
19
+ assert_equal '8', line.number
20
+ assert_equal 'app/controllers/users_controller.rb', line.file
21
+ assert_equal 'index', line.method_name
22
+ end
23
+
24
+ should "parse a string backtrace" do
25
+ string = [
26
+ "app/models/user.rb:13:in `magic'",
27
+ "app/controllers/users_controller.rb:8:in `index'"
28
+ ].join("\n")
29
+
30
+ backtrace = Airbrake::Backtrace.parse(string)
31
+
32
+ line = backtrace.lines.first
33
+ assert_equal '13', line.number
34
+ assert_equal 'app/models/user.rb', line.file
35
+ assert_equal 'magic', line.method_name
36
+
37
+ line = backtrace.lines.last
38
+ assert_equal '8', line.number
39
+ assert_equal 'app/controllers/users_controller.rb', line.file
40
+ assert_equal 'index', line.method_name
41
+ end
42
+
43
+ should "parse a windows backtrace into lines" do
44
+ array = [
45
+ "C:/Program Files/Server/app/models/user.rb:13:in `magic'",
46
+ "C:/Program Files/Server/app/controllers/users_controller.rb:8:in `index'"
47
+ ]
48
+
49
+ backtrace = Airbrake::Backtrace.parse(array)
50
+
51
+ line = backtrace.lines.first
52
+ assert_equal '13', line.number
53
+ assert_equal 'C:/Program Files/Server/app/models/user.rb', line.file
54
+ assert_equal 'magic', line.method_name
55
+
56
+ line = backtrace.lines.last
57
+ assert_equal '8', line.number
58
+ assert_equal 'C:/Program Files/Server/app/controllers/users_controller.rb', line.file
59
+ assert_equal 'index', line.method_name
60
+ end
61
+
62
+ should "be equal with equal lines" do
63
+ one = build_backtrace_array
64
+ two = one.dup
65
+
66
+ assert_equal Airbrake::Backtrace.parse(one), Airbrake::Backtrace.parse(two)
67
+ end
68
+
69
+ should "parse massive one-line exceptions into multiple lines" do
70
+ original_backtrace = Airbrake::Backtrace.
71
+ parse(["one:1:in `one'\n two:2:in `two'\n three:3:in `three`"])
72
+ expected_backtrace = Airbrake::Backtrace.
73
+ parse(["one:1:in `one'", "two:2:in `two'", "three:3:in `three`"])
74
+
75
+ assert_equal expected_backtrace, original_backtrace
76
+ end
77
+
78
+ context "with a gem root" do
79
+ setup do
80
+ @gem_root = '/root/to/gem'
81
+ Gem.path << @gem_root
82
+ end
83
+
84
+ should "filter out the gem root" do
85
+ backtrace_with_gem_root = Airbrake::Backtrace.parse(
86
+ ["#{@gem_root}/some/gem.rb:9:in `test'",
87
+ "#{@gem_root}/path/to/awesome_gem.rb:13:in `awesome'",
88
+ "/test/something.rb:55:in `hack'"],
89
+ :filters => default_filters)
90
+ backtrace_without_gem_root = Airbrake::Backtrace.parse(
91
+ ["[GEM_ROOT]/some/gem.rb:9:in `test'",
92
+ "[GEM_ROOT]/path/to/awesome_gem.rb:13:in `awesome'",
93
+ "/test/something.rb:55:in `hack'"])
94
+
95
+ assert_equal backtrace_without_gem_root, backtrace_with_gem_root
96
+ end
97
+
98
+ should "ignore empty gem paths" do
99
+ Gem.path << ""
100
+ backtrace_with_gem_root = Airbrake::Backtrace.parse(
101
+ ["#{@gem_root}/some/gem.rb:9:in `test'",
102
+ "/test/something.rb:55:in `hack'"],
103
+ :filters => default_filters)
104
+ backtrace_without_gem_root = Airbrake::Backtrace.parse(
105
+ ["[GEM_ROOT]/some/gem.rb:9:in `test'",
106
+ "/test/something.rb:55:in `hack'"])
107
+
108
+ assert_equal backtrace_without_gem_root, backtrace_with_gem_root
109
+ end
110
+ end
111
+
112
+ context "with a project root" do
113
+ setup do
114
+ @project_root = '/some/path'
115
+ Airbrake.configure {|config| config.project_root = @project_root }
116
+ end
117
+
118
+ teardown do
119
+ reset_config
120
+ end
121
+
122
+ should "filter out the project root" do
123
+ backtrace_with_root = Airbrake::Backtrace.parse(
124
+ ["#{@project_root}/app/models/user.rb:7:in `latest'",
125
+ "#{@project_root}/app/controllers/users_controller.rb:13:in `index'",
126
+ "/lib/something.rb:41:in `open'"],
127
+ :filters => default_filters)
128
+ backtrace_without_root = Airbrake::Backtrace.parse(
129
+ ["[PROJECT_ROOT]/app/models/user.rb:7:in `latest'",
130
+ "[PROJECT_ROOT]/app/controllers/users_controller.rb:13:in `index'",
131
+ "/lib/something.rb:41:in `open'"])
132
+
133
+ assert_equal backtrace_without_root, backtrace_with_root
134
+ end
135
+ end
136
+
137
+ context "with a project root equals to a part of file name" do
138
+ setup do
139
+ # Heroku-like
140
+ @project_root = '/app'
141
+ Airbrake.configure {|config| config.project_root = @project_root }
142
+ end
143
+
144
+ teardown do
145
+ reset_config
146
+ end
147
+
148
+ should "filter out the project root" do
149
+ backtrace_with_root = Airbrake::Backtrace.parse(
150
+ ["#{@project_root}/app/models/user.rb:7:in `latest'",
151
+ "#{@project_root}/app/controllers/users_controller.rb:13:in `index'",
152
+ "/lib/something.rb:41:in `open'"],
153
+ :filters => default_filters)
154
+ backtrace_without_root = Airbrake::Backtrace.parse(
155
+ ["[PROJECT_ROOT]/app/models/user.rb:7:in `latest'",
156
+ "[PROJECT_ROOT]/app/controllers/users_controller.rb:13:in `index'",
157
+ "/lib/something.rb:41:in `open'"])
158
+
159
+ assert_equal backtrace_without_root, backtrace_with_root
160
+ end
161
+ end
162
+
163
+ context "with a blank project root" do
164
+ setup do
165
+ Airbrake.configure {|config| config.project_root = '' }
166
+ end
167
+
168
+ teardown do
169
+ reset_config
170
+ end
171
+
172
+ should "not filter line numbers with respect to any project root" do
173
+ backtrace = ["/app/models/user.rb:7:in `latest'",
174
+ "/app/controllers/users_controller.rb:13:in `index'",
175
+ "/lib/something.rb:41:in `open'"]
176
+
177
+ backtrace_with_root =
178
+ Airbrake::Backtrace.parse(backtrace, :filters => default_filters)
179
+
180
+ backtrace_without_root =
181
+ Airbrake::Backtrace.parse(backtrace)
182
+
183
+ assert_equal backtrace_without_root, backtrace_with_root
184
+ end
185
+ end
186
+
187
+ should "remove notifier trace" do
188
+ inside_notifier = ['lib/airbrake.rb:13:in `voodoo`']
189
+ outside_notifier = ['users_controller:8:in `index`']
190
+
191
+ without_inside = Airbrake::Backtrace.parse(outside_notifier)
192
+ with_inside = Airbrake::Backtrace.parse(inside_notifier + outside_notifier,
193
+ :filters => default_filters)
194
+
195
+ assert_equal without_inside, with_inside
196
+ end
197
+
198
+ should "run filters on the backtrace" do
199
+ filters = [lambda { |line| line.sub('foo', 'bar') }]
200
+ input = Airbrake::Backtrace.parse(["foo:13:in `one'", "baz:14:in `two'"],
201
+ :filters => filters)
202
+ expected = Airbrake::Backtrace.parse(["bar:13:in `one'", "baz:14:in `two'"])
203
+ assert_equal expected, input
204
+ end
205
+
206
+ def build_backtrace_array
207
+ ["app/models/user.rb:13:in `magic'",
208
+ "app/controllers/users_controller.rb:8:in `index'"]
209
+ end
210
+
211
+ def default_filters
212
+ Airbrake::Configuration::DEFAULT_BACKTRACE_FILTERS
213
+ end
214
+
215
+ end
@@ -0,0 +1,44 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ silence_warnings { require 'capistrano/configuration' }
4
+ require 'airbrake/capistrano'
5
+
6
+ class CapistranoTest < Test::Unit::TestCase
7
+ def setup
8
+ super
9
+ reset_config
10
+
11
+ # Save value to avoid polluting ENV for future tests
12
+ @old_user = ENV['USER']
13
+ ENV['USER'] = %q[D'Angelo "D" Barksdale]
14
+
15
+ @configuration = Capistrano::Configuration.new
16
+ Airbrake::Capistrano.load_into(@configuration)
17
+ @configuration.dry_run = true
18
+ end
19
+
20
+ should "define airbrake:deploy task" do
21
+ assert_not_nil @configuration.find_task('airbrake:deploy')
22
+ end
23
+
24
+ should "log when calling airbrake:deploy task" do
25
+ @configuration.set(:current_revision, '084505b1c0e0bcf1526e673bb6ac99fbcb18aecc')
26
+ @configuration.set(:repository, 'repository')
27
+ @configuration.set(:rails_env, :production)
28
+ @configuration.set(:release_path, '/home/deploy/rails_app/hoptoad')
29
+ io = StringIO.new
30
+ logger = Capistrano::Logger.new(:output => io)
31
+ logger.level = Capistrano::Logger::MAX_LEVEL
32
+
33
+ @configuration.logger = logger
34
+ @configuration.find_and_execute_task('airbrake:deploy')
35
+
36
+ assert io.string.include?('** Notifying Airbrake of Deploy')
37
+ assert io.string.include?('TO=production')
38
+ assert io.string.include?('** Airbrake Notification Complete')
39
+ assert io.string.include?(%q[D\'Angelo\ \"D\"\ Barksdale])
40
+ end
41
+
42
+ # Return ENV['USER'] to its original value
43
+ def teardown; ENV['USER'] = @old_user end
44
+ end