Permalink
Browse files

Insert the Hoptoad Error Number into the response if possible.

  • Loading branch information...
1 parent 0fa53cd commit 68f51a4225cb051ee60bb4908bae47ba1a8a3d4f @jyurek jyurek committed Jan 21, 2011
@@ -206,6 +206,12 @@ def rails_non_initializer_hoptoad_config_file
perform_request(uri, environment)
end
+Given /^the response page for a "([^\"]*)" error is$/ do |error, html|
+ File.open(File.join(RAILS_ROOT, "public", "#{error}.html"), "w") do |file|
+ file.write(html)
+ end
+end
+
Then /^I should receive the following Hoptoad notification:$/ do |table|
exceptions = @terminal.output.scan(%r{Recieved the following exception:\n([^\n]*)\n}m)
exceptions.should_not be_empty
@@ -3,5 +3,13 @@ require 'sham_rack'
ShamRack.at("hoptoadapp.com") do |env|
xml = env['rack.input'].read
puts "Recieved the following exception:\n#{xml}"
- ["200 OK", { "Content-type" => "text/xml" }, "<notice/>"]
+ response = <<-end_xml
+<?xml version="1.0" encoding="UTF-8"?>
+<notice>
+ <error-id type="integer">3799307</error-id>
+ <url>http://sample.hoptoadapp.com/errors/3799307/notices/643732254</url>
+ <id type="integer">643732254</id>
+</notice>
+ end_xml
+ ["200 OK", { "Content-type" => "text/xml" }, response]
end
@@ -63,6 +63,7 @@ def echo(string)
def build_and_install_gem(gemspec)
pkg_dir = File.join(TEMP_DIR, 'pkg')
FileUtils.mkdir_p(pkg_dir)
+ `rake gemspec`
output = `gem build #{gemspec} 2>&1`
gem_file = Dir.glob("*.gem").first
unless gem_file
@@ -0,0 +1,21 @@
+Feature: Inform the user of the hoptoad notice that was just created
+
+ Background:
+ Given I have built and installed the "hoptoad_notifier" gem
+
+ Scenario: Rescue an exception in a controller
+ When I generate a new Rails application
+ And I configure the Hoptoad shim
+ And I configure my application to require the "hoptoad_notifier" gem
+ And I run the hoptoad generator with "-k myapikey"
+ And I define a response for "TestController#index":
+ """
+ raise RuntimeError, "some message"
+ """
+ And the response page for a "500" error is
+ """
+ <!-- HOPTOAD ERROR -->
+ """
+ And I route "/test/index" to "test#index"
+ And I perform a request to "http://example.com:123/test/index?param=value"
+ Then I should see "Error #3799307"
View
@@ -12,6 +12,7 @@
require 'hoptoad_notifier/sender'
require 'hoptoad_notifier/backtrace'
require 'hoptoad_notifier/rack'
+require 'hoptoad_notifier/user_informer'
require 'hoptoad_notifier/railtie' if defined?(Rails::Railtie)
@@ -26,12 +26,14 @@ def call(env)
begin
response = @app.call(env)
rescue Exception => raised
- HoptoadNotifier.notify_or_ignore(raised, :rack_env => env)
+ error_id = HoptoadNotifier.notify_or_ignore(raised, :rack_env => env)
+ env['hoptoad.error_id'] = error_id
raise
end
if env['rack.exception']
- HoptoadNotifier.notify_or_ignore(env['rack.exception'], :rack_env => env)
+ error_id = HoptoadNotifier.notify_or_ignore(env['rack.exception'], :rack_env => env)
+ env['hoptoad.error_id'] = error_id
end
response
@@ -23,6 +23,8 @@ def self.initialize
if defined?(::Rails.configuration) && ::Rails.configuration.respond_to?(:middleware)
::Rails.configuration.middleware.insert_after 'ActionController::Failsafe',
HoptoadNotifier::Rack
+ ::Rails.configuration.middleware.insert_after 'Rack::Lock',
+ HoptoadNotifier::UserInformer
end
HoptoadNotifier.configure(true) do |config|
@@ -14,7 +14,8 @@ def self.included(base) #:nodoc:
# any custom processing that is defined with Rails 2's exception helpers.
def rescue_action_in_public_with_hoptoad(exception)
unless hoptoad_ignore_user_agent?
- HoptoadNotifier.notify_or_ignore(exception, hoptoad_request_data)
+ error_id = HoptoadNotifier.notify_or_ignore(exception, hoptoad_request_data)
+ request.env['hoptoad.error_id'] = error_id
end
rescue_action_in_public_without_hoptoad(exception)
end
@@ -9,6 +9,7 @@ class Railtie < Rails::Railtie
initializer "hoptoad.use_rack_middleware" do |app|
app.config.middleware.use "HoptoadNotifier::Rack"
+ app.config.middleware.insert_after "Rack::Lock", "HoptoadNotifier::UserInformer"
end
config.after_initialize do
@@ -46,6 +46,11 @@ def send_to_hoptoad(data)
else
log :error, "Failure: #{response.class}", response
end
+
+ if response && response.respond_to?(:body)
+ error_id = response.body.match(%r{<error-id[^>]*>(.*?)</error-id>})
+ error_id[1] if error_id
+ end
end
private
@@ -0,0 +1,25 @@
+module HoptoadNotifier
+ class UserInformer
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ response = @app.call(env)
+ if env['hoptoad.error_id']
+ new_response = []
+ original_content_length = 0
+ modified_content_length = 0
+ response[2].each do |chunk|
+ original_content_length += chunk.length
+ new_response << chunk.to_s.gsub("<!-- HOPTOAD ERROR -->", "Error ##{env["hoptoad.error_id"].to_s}")
+ modified_content_length += new_response.last.length
+ end
+ response[1]['Content-Length'] = modified_content_length.to_s
+ response[2] = new_response
+ end
+ response
+ end
+ end
+end
+
View
@@ -25,6 +25,8 @@ def build_controller_class(&definition)
def assert_sent_hash(hash, xpath)
hash.each do |key, value|
+ next if key.match(/^hoptoad\./) # We added this key.
+
element_xpath = "#{xpath}/var[@key = '#{key}']"
if value.respond_to?(:to_hash)
assert_sent_hash value.to_hash, element_xpath
View
@@ -7,6 +7,7 @@
gem "nokogiri", "= 1.4.3.1"
gem "shoulda", "= 2.11.3"
gem 'bourne', '>= 1.0'
+gem "sham_rack", "~> 1.3.0"
$LOAD_PATH << File.join(File.dirname(__FILE__), *%w[.. vendor ginger lib])
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
@@ -25,6 +26,7 @@
require 'nokogiri'
require 'rack'
require 'bourne'
+require 'sham_rack'
require "hoptoad_notifier"
View
@@ -16,11 +16,10 @@ def send_exception(args = {})
notice = args.delete(:notice) || build_notice_data
sender = args.delete(:sender) || build_sender(args)
sender.send_to_hoptoad(notice)
- sender
end
- def stub_http
- response = stub(:body => 'body')
+ def stub_http(options = {})
+ response = stub(:body => options[:body] || 'body')
http = stub(:post => response,
:read_timeout= => nil,
:open_timeout= => nil,
@@ -58,6 +57,17 @@ def stub_http
end
end
+ should "return the created group's id on successful posting" do
+ http = stub_http(:body => '<error-id type="integer">3799307</error-id>')
+ assert_equal "3799307", send_exception(:secure => false)
+ end
+
+ should "return nil on failed posting" do
+ http = stub_http
+ http.stubs(:post).raises(Errno::ECONNREFUSED)
+ assert_equal nil, send_exception(:secure => false)
+ end
+
should "not fail when posting and a timeout exception occurs" do
http = stub_http
http.stubs(:post).raises(TimeoutError)
View
@@ -0,0 +1,29 @@
+require File.dirname(__FILE__) + '/helper'
+
+class UserInformerTest < Test::Unit::TestCase
+ should "modify output if there is a hoptoad id" do
+ main_app = lambda do |env|
+ env['hoptoad.error_id'] = 1
+ [200, {}, "<!-- HOPTOAD ERROR -->"]
+ end
+ informer_app = HoptoadNotifier::UserInformer.new(main_app)
+
+ ShamRack.mount(informer_app, "example.com")
+
+ response = Net::HTTP.get_response(URI.parse("http://example.com/"))
+ assert_equal "Error #1", response.body
+ assert_equal 8, response["Content-Length"].to_i
+ end
+
+ should "not modify output if there is no hoptoad id" do
+ main_app = lambda do |env|
+ [200, {}, "<!-- HOPTOAD ERROR -->"]
+ end
+ informer_app = HoptoadNotifier::UserInformer.new(main_app)
+
+ ShamRack.mount(informer_app, "example.com")
+
+ response = Net::HTTP.get_response(URI.parse("http://example.com/"))
+ assert_equal "<!-- HOPTOAD ERROR -->", response.body
+ end
+end

0 comments on commit 68f51a4

Please sign in to comment.