honeybadger 1.0.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 (65) hide show
  1. data/Gemfile +13 -0
  2. data/Gemfile.lock +114 -0
  3. data/Guardfile +5 -0
  4. data/MIT-LICENSE +22 -0
  5. data/README.md +271 -0
  6. data/Rakefile +261 -0
  7. data/SUPPORTED_RAILS_VERSIONS +26 -0
  8. data/TESTING.md +33 -0
  9. data/features/metal.feature +18 -0
  10. data/features/rack.feature +56 -0
  11. data/features/rails.feature +211 -0
  12. data/features/rake.feature +27 -0
  13. data/features/sinatra.feature +29 -0
  14. data/features/step_definitions/file_steps.rb +10 -0
  15. data/features/step_definitions/metal_steps.rb +23 -0
  16. data/features/step_definitions/rack_steps.rb +23 -0
  17. data/features/step_definitions/rails_application_steps.rb +394 -0
  18. data/features/step_definitions/rake_steps.rb +17 -0
  19. data/features/support/env.rb +17 -0
  20. data/features/support/honeybadger_shim.rb.template +8 -0
  21. data/features/support/rails.rb +201 -0
  22. data/features/support/rake/Rakefile +68 -0
  23. data/features/support/terminal.rb +107 -0
  24. data/generators/honeybadger/honeybadger_generator.rb +94 -0
  25. data/generators/honeybadger/lib/insert_commands.rb +34 -0
  26. data/generators/honeybadger/lib/rake_commands.rb +24 -0
  27. data/generators/honeybadger/templates/capistrano_hook.rb +6 -0
  28. data/generators/honeybadger/templates/honeybadger_tasks.rake +25 -0
  29. data/generators/honeybadger/templates/initializer.rb +6 -0
  30. data/honeybadger.gemspec +109 -0
  31. data/lib/honeybadger.rb +162 -0
  32. data/lib/honeybadger/backtrace.rb +123 -0
  33. data/lib/honeybadger/capistrano.rb +43 -0
  34. data/lib/honeybadger/configuration.rb +273 -0
  35. data/lib/honeybadger/notice.rb +314 -0
  36. data/lib/honeybadger/rack.rb +55 -0
  37. data/lib/honeybadger/rails.rb +34 -0
  38. data/lib/honeybadger/rails/action_controller_catcher.rb +30 -0
  39. data/lib/honeybadger/rails/controller_methods.rb +69 -0
  40. data/lib/honeybadger/rails/middleware/exceptions_catcher.rb +29 -0
  41. data/lib/honeybadger/rails3_tasks.rb +84 -0
  42. data/lib/honeybadger/railtie.rb +45 -0
  43. data/lib/honeybadger/rake_handler.rb +65 -0
  44. data/lib/honeybadger/sender.rb +120 -0
  45. data/lib/honeybadger/shared_tasks.rb +36 -0
  46. data/lib/honeybadger/tasks.rb +82 -0
  47. data/lib/honeybadger_tasks.rb +65 -0
  48. data/lib/rails/generators/honeybadger/honeybadger_generator.rb +99 -0
  49. data/rails/init.rb +1 -0
  50. data/resources/README.md +34 -0
  51. data/resources/ca-bundle.crt +3376 -0
  52. data/script/integration_test.rb +38 -0
  53. data/test/test_helper.rb +143 -0
  54. data/test/unit/backtrace_test.rb +180 -0
  55. data/test/unit/capistrano_test.rb +34 -0
  56. data/test/unit/configuration_test.rb +201 -0
  57. data/test/unit/honeybadger_tasks_test.rb +163 -0
  58. data/test/unit/logger_test.rb +72 -0
  59. data/test/unit/notice_test.rb +406 -0
  60. data/test/unit/notifier_test.rb +245 -0
  61. data/test/unit/rack_test.rb +56 -0
  62. data/test/unit/rails/action_controller_catcher_test.rb +300 -0
  63. data/test/unit/rails_test.rb +35 -0
  64. data/test/unit/sender_test.rb +257 -0
  65. metadata +315 -0
@@ -0,0 +1,23 @@
1
+ Given /^the following Rack app:$/ do |definition|
2
+ File.open(RACK_FILE, 'w') { |file| file.write(definition) }
3
+ end
4
+
5
+ When /^I perform a Rack request to "([^\"]*)"$/ do |url|
6
+ shim_file = File.join(PROJECT_ROOT, 'features', 'support', 'honeybadger_shim.rb.template')
7
+ request_file = File.join(TEMP_DIR, 'rack_request.rb')
8
+ File.open(request_file, 'w') do |file|
9
+ file.puts "require 'rubygems'"
10
+ file.puts IO.read(shim_file)
11
+ file.puts IO.read(RACK_FILE)
12
+ file.puts "env = Rack::MockRequest.env_for(#{url.inspect})"
13
+ file.puts "status, headers, body = app.call(env)"
14
+ file.puts %{puts "HTTP \#{status}"}
15
+ file.puts %{headers.each { |key, value| puts "\#{key}: \#{value}"}}
16
+ file.puts "body.each { |part| print part }"
17
+ end
18
+ @terminal.run("ruby #{request_file}")
19
+ end
20
+
21
+ Then /^I should receive a Honeybadger notification for rack$/ do
22
+ Then %{I should see "You have accessed a deleted account."}
23
+ end
@@ -0,0 +1,394 @@
1
+ require 'uri'
2
+ require 'active_support/core_ext/string/inflections'
3
+
4
+ Given /^I have built and installed the "([^\"]*)" gem$/ do |gem_name|
5
+ @terminal.build_and_install_gem(File.join(PROJECT_ROOT, "#{gem_name}.gemspec"))
6
+ end
7
+
8
+ When /^I generate a new Rails application$/ do
9
+ @terminal.cd(TEMP_DIR)
10
+
11
+ rails3 = version_string =~ /^3/
12
+
13
+ if rails3
14
+ rails_create_command = 'new'
15
+ else
16
+ rails_create_command = ''
17
+ end
18
+
19
+ load_rails = <<-RUBY
20
+ gem 'rails', '#{version_string}'; \
21
+ load Gem.bin_path('#{version_string >= "3.2.0" ? "railties" : "rails"}', 'rails', '#{version_string}')
22
+ RUBY
23
+
24
+ @terminal.run(%{ruby -rrubygems -rthread -e "#{load_rails.strip!}" #{rails_create_command} rails_root})
25
+ if rails_root_exists?
26
+ @terminal.echo("Generated a Rails #{version_string} application")
27
+ else
28
+ raise "Unable to generate a Rails application:\n#{@terminal.output}"
29
+ end
30
+ require_thread
31
+ if version_string >= "3.1.0"
32
+ When %{I configure my application to require the "therubyracer" gem with version "0.10.1"}
33
+ elsif version_string == "2.3.14"
34
+ monkeypatch_old_version
35
+ end
36
+ config_gem_dependencies unless rails3
37
+ end
38
+
39
+ When /^I run the honeybadger generator with "([^\"]*)"$/ do |generator_args|
40
+ if rails3?
41
+ When %{I run "./script/rails generate honeybadger #{generator_args}"}
42
+ else
43
+ When %{I run "./script/generate honeybadger #{generator_args}"}
44
+ end
45
+ end
46
+
47
+ When /^I print the console output$/ do
48
+ puts @terminal.output
49
+ end
50
+
51
+ Given /^I have installed the "([^\"]*)" gem$/ do |gem_name|
52
+ @terminal.install_gem(gem_name)
53
+ end
54
+
55
+
56
+ When /^I configure my application to require the "capistrano" gem if necessary$/ do
57
+ When %{I configure my application to require the "capistrano" gem} if version_string >= "3.0.0"
58
+ end
59
+
60
+ When /^I configure my application to require the "([^\"]*)" gem(?: with version "(.+)")?$/ do |gem_name, version|
61
+ if rails_manages_gems?
62
+ config_gem(gem_name, version)
63
+ elsif bundler_manages_gems?
64
+ bundle_gem(gem_name, version)
65
+ else
66
+ File.open(environment_path, 'a') do |file|
67
+ file.puts
68
+ file.puts("require 'honeybadger'")
69
+ file.puts("require 'honeybadger/rails'")
70
+ end
71
+
72
+ unless rails_finds_generators_in_gems?
73
+ FileUtils.cp_r(File.join(PROJECT_ROOT, 'generators'), File.join(rails_root, 'lib'))
74
+ end
75
+ end
76
+ end
77
+
78
+ When /^I run "([^\"]*)"$/ do |command|
79
+ @terminal.cd(rails_root)
80
+ @terminal.run(command)
81
+ end
82
+
83
+ Then /^I should receive a Honeybadger notification$/ do
84
+ Then %{I should see "** [Honeybadger] Response from Honeybadger:"}
85
+ And %{I should see "123456789"}
86
+ end
87
+
88
+ Then /^I should receive two Honeybadger notifications$/ do
89
+ @terminal.output.scan(/\[Honeybadger\] Response from Honeybadger:/).size.should == 2
90
+ end
91
+
92
+ When /^I configure the Honeybadger shim$/ do
93
+ if bundler_manages_gems?
94
+ bundle_gem("sham_rack")
95
+ end
96
+
97
+ shim_file = File.join(PROJECT_ROOT, 'features', 'support', 'honeybadger_shim.rb.template')
98
+ if rails_supports_initializers?
99
+ target = File.join(rails_root, 'config', 'initializers', 'honeybadger_shim.rb')
100
+ FileUtils.cp(shim_file, target)
101
+ else
102
+ File.open(environment_path, 'a') do |file|
103
+ file.puts
104
+ file.write IO.read(shim_file)
105
+ end
106
+ end
107
+ end
108
+
109
+ When /^I configure the notifier to use "([^\"]*)" as an API key$/ do |api_key|
110
+ steps %{
111
+ When I configure the notifier to use the following configuration lines:
112
+ """
113
+ config.api_key = #{api_key.inspect}
114
+ """
115
+ }
116
+ end
117
+
118
+ When /^I configure the notifier to use the following configuration lines:$/ do |configuration_lines|
119
+ if rails_manages_gems?
120
+ requires = ''
121
+ else
122
+ requires = "require 'honeybadger'"
123
+ end
124
+
125
+ initializer_code = <<-EOF
126
+ #{requires}
127
+ Honeybadger.configure do |config|
128
+ #{configuration_lines}
129
+ end
130
+ EOF
131
+
132
+ if rails_supports_initializers?
133
+ File.open(rails_initializer_file, 'w') { |file| file.write(initializer_code) }
134
+ else
135
+ File.open(environment_path, 'a') do |file|
136
+ file.puts
137
+ file.puts initializer_code
138
+ end
139
+ end
140
+
141
+ end
142
+
143
+ def rails_initializer_file
144
+ File.join(rails_root, 'config', 'initializers', 'honeybadger.rb')
145
+ end
146
+
147
+ def rails_non_initializer_honeybadger_config_file
148
+ File.join(rails_root, 'config', 'honeybadger.rb')
149
+ end
150
+
151
+ Then /^I should see "([^\"]*)"$/ do |expected_text|
152
+ unless @terminal.output.include?(expected_text)
153
+ raise("Got terminal output:\n#{@terminal.output}\n\nExpected output:\n#{expected_text}")
154
+ end
155
+ end
156
+
157
+ Then /^I should not see "([^\"]*)"$/ do |unexpected_text|
158
+ if @terminal.output.include?(unexpected_text)
159
+ raise("Got terminal output:\n#{@terminal.output}\n\nDid not expect the following output:\n#{unexpected_text}")
160
+ end
161
+ end
162
+
163
+ When /^I uninstall the "([^\"]*)" gem$/ do |gem_name|
164
+ @terminal.uninstall_gem(gem_name)
165
+ end
166
+
167
+ When /^I unpack the "([^\"]*)" gem$/ do |gem_name|
168
+ if bundler_manages_gems?
169
+ @terminal.cd(rails_root)
170
+ @terminal.run("bundle pack")
171
+ elsif rails_manages_gems?
172
+ @terminal.cd(rails_root)
173
+ @terminal.run("rake gems:unpack GEM=#{gem_name}")
174
+ else
175
+ vendor_dir = File.join(rails_root, 'vendor', 'gems')
176
+ FileUtils.mkdir_p(vendor_dir)
177
+ @terminal.cd(vendor_dir)
178
+ @terminal.run("gem unpack #{gem_name}")
179
+ gem_path =
180
+ Dir.glob(File.join(rails_root, 'vendor', 'gems', "#{gem_name}-*", 'lib')).first
181
+ File.open(environment_path, 'a') do |file|
182
+ file.puts
183
+ file.puts("$: << #{gem_path.inspect}")
184
+ end
185
+ end
186
+ end
187
+
188
+ When /^I install cached gems$/ do
189
+ if bundler_manages_gems?
190
+ Then %{I run "bundle install"}
191
+ end
192
+ end
193
+
194
+ When /^I install the "([^\"]*)" plugin$/ do |plugin_name|
195
+ FileUtils.mkdir_p("#{rails_root}/vendor/plugins/#{plugin_name}")
196
+ end
197
+
198
+ When /^I define a response for "([^\"]*)":$/ do |controller_and_action, definition|
199
+ controller_class_name, action = controller_and_action.split('#')
200
+ controller_name = controller_class_name.underscore
201
+ controller_file_name = File.join(rails_root, 'app', 'controllers', "#{controller_name}.rb")
202
+ File.open(controller_file_name, "w") do |file|
203
+ file.puts "class #{controller_class_name} < ApplicationController"
204
+ file.puts "def consider_all_requests_local; false; end"
205
+ file.puts "def local_request?; false; end"
206
+ file.puts "def #{action}"
207
+ file.puts definition
208
+ file.puts "end"
209
+ file.puts "end"
210
+ end
211
+ end
212
+
213
+ When /^I perform a request to "([^\"]*)"$/ do |uri|
214
+ perform_request(uri)
215
+ end
216
+
217
+ When /^I perform a request to "([^\"]*)" in the "([^\"]*)" environment$/ do |uri, environment|
218
+ perform_request(uri, environment)
219
+ end
220
+
221
+ Given /^the response page for a "([^\"]*)" error is$/ do |error, html|
222
+ File.open(File.join(rails_root, "public", "#{error}.html"), "w") do |file|
223
+ file.write(html)
224
+ end
225
+ end
226
+
227
+ Then /^I should receive the following Honeybadger notification:$/ do |table|
228
+ exceptions = @terminal.output.scan(%r{Recieved the following exception:\n([^\n]*)\n}m)
229
+ exceptions.should_not be_empty
230
+
231
+ xml = exceptions.last[0]
232
+ doc = Nokogiri::XML.parse(xml)
233
+
234
+ hash = table.transpose.hashes.first
235
+
236
+ doc.should have_content('//error/message', hash['error message'])
237
+ doc.should have_content('//error/class', hash['error class'])
238
+ doc.should have_content('//request/url', hash['url'])
239
+
240
+ doc.should have_content('//component', hash['component']) if hash['component']
241
+ doc.should have_content('//action', hash['action']) if hash['action']
242
+ doc.should have_content('//server-environment/project-root', hash['project-root']) if hash['project-root']
243
+
244
+ if hash['session']
245
+ session_key, session_value = hash['session'].split(': ')
246
+ doc.should have_content('//request/session/var/@key', session_key)
247
+ doc.should have_content('//request/session/var', session_value)
248
+ end
249
+
250
+ if hash['parameters']
251
+ param_key, param_value = hash['parameters'].split(': ')
252
+ doc.should have_content('//request/params/var/@key', param_key)
253
+ doc.should have_content('//request/params/var', param_value)
254
+ end
255
+ end
256
+
257
+ Then /^I should see the Rails version$/ do
258
+ Then %{I should see "[Rails: #{rails_version}]"}
259
+ end
260
+
261
+ Then /^I should see that "([^\"]*)" is not considered a framework gem$/ do |gem_name|
262
+ Then %{I should not see "[R] #{gem_name}"}
263
+ end
264
+
265
+ Then /^the command should have run successfully$/ do
266
+ @terminal.status.exitstatus.should == 0
267
+ end
268
+
269
+ When /^I route "([^\"]*)" to "([^\"]*)"$/ do |path, controller_action_pair|
270
+ route = if rails3?
271
+ %(match "#{path}", :to => "#{controller_action_pair}")
272
+ else
273
+ controller, action = controller_action_pair.split('#')
274
+ %(map.connect "#{path}", :controller => "#{controller}", :action => "#{action}")
275
+ end
276
+ routes_file = File.join(rails_root, "config", "routes.rb")
277
+ File.open(routes_file, "r+") do |file|
278
+ content = file.read
279
+ content.gsub!(/^end$/, " #{route}\nend")
280
+ file.rewind
281
+ file.write(content)
282
+ end
283
+ end
284
+
285
+ Then /^"([^\"]*)" should not contain "([^\"]*)"$/ do |file_path, text|
286
+ actual_text = IO.read(File.join(rails_root, file_path))
287
+ if actual_text.include?(text)
288
+ raise "Didn't expect text:\n#{actual_text}\nTo include:\n#{text}"
289
+ end
290
+ end
291
+
292
+ Then /^my Honeybadger configuration should contain the following line:$/ do |line|
293
+ configuration_file = if rails_supports_initializers?
294
+ rails_initializer_file
295
+ else
296
+ rails_non_initializer_honeybadger_config_file
297
+ # environment_path
298
+ end
299
+
300
+ configuration = File.read(configuration_file)
301
+ if ! configuration.include?(line.strip)
302
+ raise "Expected text:\n#{configuration}\nTo include:\n#{line}\nBut it didn't."
303
+ end
304
+ end
305
+
306
+ When /^I set the environment variable "([^\"]*)" to "([^\"]*)"$/ do |environment_variable, value|
307
+ @terminal.environment_variables[environment_variable] = value
308
+ end
309
+
310
+ When /^I configure the Heroku rake shim$/ do
311
+ @terminal.invoke_heroku_rake_tasks_locally = true
312
+ end
313
+
314
+ When /^I configure the Heroku gem shim with "([^\"]*)"( and multiple app support)?$/ do |api_key, multi_app|
315
+ heroku_script_bin = File.join(TEMP_DIR, "bin")
316
+ FileUtils.mkdir_p(heroku_script_bin)
317
+ heroku_script = File.join(heroku_script_bin, "heroku")
318
+ heroku_env_vars = <<-VARS
319
+ HONEYBADGER_API_KEY => myapikey
320
+ APP_NAME => cold-moon-2929
321
+ BUNDLE_WITHOUT => development:test
322
+ COMMIT_HASH => lj32j42ss9332jfa2
323
+ DATABASE_URL => postgres://fchovwjcyb:QLPVWmBBbf4hCG_YMrtV@ec3-107-28-193-23.compute-1.amazonaws.com/fhcvojwwcyb
324
+ LANG => en_US.UTF-8
325
+ LAST_GIT_BY => kensa
326
+ RACK_ENV => production
327
+ SHARED_DATABASE_URL => postgres://fchovwjcyb:QLPVwMbbbF8Hcg_yMrtV@ec2-94-29-181-224.compute-1.amazonaws.com/fhcvojcwwyb
328
+ STACK => bamboo-mri-1.9.2
329
+ URL => cold-moon-2929.heroku.com
330
+ VARS
331
+ single_app_script = <<-SINGLE
332
+ #!/bin/bash
333
+ if [ $1 == 'config' ]
334
+ then
335
+ echo "#{heroku_env_vars}"
336
+ fi
337
+ SINGLE
338
+
339
+ multi_app_script = <<-MULTI
340
+ #!/bin/bash
341
+ if [[ $1 == 'config' && $2 == '--app' ]]
342
+ then
343
+ echo "#{heroku_env_vars}"
344
+ fi
345
+ MULTI
346
+
347
+ File.open(heroku_script, "w") do |f|
348
+ if multi_app
349
+ f.puts multi_app_script
350
+ else
351
+ f.puts single_app_script
352
+ end
353
+ end
354
+ FileUtils.chmod(0755, heroku_script)
355
+ @terminal.prepend_path(heroku_script_bin)
356
+ end
357
+
358
+ When /^I configure the application to filter parameter "([^\"]*)"$/ do |parameter|
359
+ if rails3?
360
+ application_filename = File.join(rails_root, 'config', 'application.rb')
361
+ application_lines = File.open(application_filename).readlines
362
+
363
+ application_definition_line = application_lines.detect { |line| line =~ /Application/ }
364
+ application_definition_line_index = application_lines.index(application_definition_line)
365
+
366
+ application_lines.insert(application_definition_line_index + 1,
367
+ " config.filter_parameters += [#{parameter.inspect}]")
368
+
369
+ File.open(application_filename, "w") do |file|
370
+ file.puts application_lines.join("\n")
371
+ end
372
+ else
373
+ controller_filename = application_controller_filename
374
+ controller_lines = File.open(controller_filename).readlines
375
+
376
+ controller_definition_line = controller_lines.detect { |line| line =~ /ApplicationController/ }
377
+ controller_definition_line_index = controller_lines.index(controller_definition_line)
378
+
379
+ controller_lines.insert(controller_definition_line_index + 1,
380
+ " filter_parameter_logging #{parameter.inspect}")
381
+
382
+ File.open(controller_filename, "w") do |file|
383
+ file.puts controller_lines.join("\n")
384
+ end
385
+ end
386
+ end
387
+
388
+ When /^I configure usage of Honeybadger$/ do
389
+ When %{I configure my application to require the "honeybadger" gem}
390
+ When %{I run the honeybadger generator with "-k myapikey"}
391
+
392
+ # flush the results of setting up Honeybadger (generates notification)
393
+ @terminal.flush!
394
+ end
@@ -0,0 +1,17 @@
1
+ When /I run rake with (.+)/ do |command|
2
+ @rake_command = "rake #{command.gsub(' ','_')}"
3
+ @rake_result = `cd features/support/rake && GEM_HOME=#{BUILT_GEM_ROOT} #{@rake_command} 2>&1`
4
+ end
5
+
6
+ Then /Honeybadger should (|not) ?catch the exception/ do |condition|
7
+ if condition=='not'
8
+ @rake_result.should_not =~ /^honeybadger/
9
+ else
10
+ @rake_result.should =~ /^honeybadger/
11
+ end
12
+ end
13
+
14
+ Then /Honeybadger should send the rake command line as the component name/ do
15
+ component = @rake_result.match(/^honeybadger (.*)$/)[1]
16
+ component.should == @rake_command
17
+ end
@@ -0,0 +1,17 @@
1
+ require 'active_support'
2
+ require 'rspec'
3
+
4
+ PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..')).freeze
5
+ TEMP_DIR = File.join(PROJECT_ROOT, 'tmp').freeze
6
+ LOCAL_RAILS_ROOT = File.join(TEMP_DIR, 'rails_root').freeze
7
+ BUILT_GEM_ROOT = File.join(TEMP_DIR, 'built_gems').freeze
8
+ LOCAL_GEM_ROOT = File.join(TEMP_DIR, 'local_gems').freeze
9
+ RACK_FILE = File.join(TEMP_DIR, 'rack_app.rb').freeze
10
+
11
+ Before do
12
+ FileUtils.mkdir_p(TEMP_DIR)
13
+ FileUtils.rm_rf(BUILT_GEM_ROOT)
14
+ FileUtils.rm_rf(LOCAL_RAILS_ROOT)
15
+ FileUtils.rm_f(RACK_FILE)
16
+ FileUtils.mkdir_p(BUILT_GEM_ROOT)
17
+ end