How to test 404 Sinatra::NotFound errors with Rack::Test? - ruby

I have an application that raises 404 Sinatra::NotFound errors on production when the route is missing.
However, the following test passes:
it 'should not raise error' do
expect{ get '/unknown_path' }.to_not raise_error
end
Why don't 404 Sinatra::NotFound errors get raised in the test?
The following does raise the error and cause the test to fail:
get '/unknown_path' do
raise 'error'
end
How to test for 404 Sinatra::NotFound errors?

The issue is that get /unknown_path' is not actually raising an error – it's only receiving a 404 request.
From Sinatra: README
The error handler is invoked any time an exception is raised from a route block or a filter. The exception object can be obtained from the sinatra.error Rack variable...
Your test is testing for an actual error (this is what raise_error does), while Sinatra is squashing the error – otherwise, every time someone 404'd the server would crash!
Check out the Sinatra testing guide for better direction on forming your tests. The basic idea is that using get ... in a test sets the last_response local variable, which can then be tested for equality, etc.
last_response has a status attribute, so (like was mentioned in another answer) you can just test to make sure that last_response.status equals 404.
Edit:
I wasn't really clear about this. In testing mode, the application does actually raise errors.
From Sinatra Settings
raise_errors
raise exceptions (will stop application). Enabled by default when environment is set to "test", disabled otherwise.
So you don't actually want to raise just any error, but raise Sinatra::NotFound.new("Not found!") to raise the specific type of error. The Sinatra::NotFound error will trigger the 404 handler. Sinatra Error Handling

Try this:
get '/unknown_path'
assert_equal last_response.status, 404

Related

How do I send Bugsnag notifices to stderr?

I'm working on a Ruby software which may catch some errors (exceptions) and use Bugsnag to record the event in the Bugsnag logs.
For example, I may have something like this:
begin
[...snip...]
rescue StandardError => e
Bugsnag.notify(e)
end
What I'd like to be able to do is redirect the message logged by that line of code to my console. That way I could get it to my log file and then search on it and see what's before/after it and make sure things are working as expected.
Is there a way to setup Bugsnag to get such functionality?
I suggest using an On Error Callback. This callback will be executed for every handled and unhandled exception.
Bugsnag.configure do |config|
config.add_on_error(proc do |event|
# redirect message to your console here
end)
end

Rack-timeout results in 500 instead of 503

I'm using heroku's rack-timeout gem, along with dynamic error pages as described here.
However, when timeout raises an exception, it get's routed as a 500 error rather than 503.
I could catch the exception with a rescue_from in my application controller and manually route to errors#503, but that would prevent plugins like Rollbar from recording the exception.
Is there a way to get the correct error page rendered and ensure plugins like Rollbar still get wind of the exception?
I ended up using the rambulance gem, which provides a simple configuration option to solve this:
# config/initializers/rambulance.rb
Rambulance.setup do |config|
config.rescue_responses = {
"Rack::Timeout::RequestTimeoutException" => :service_unavailable
}
end
The author has also written up some good reasons why not to use the approach I was previously using:
Remove custom errors page section from the guides
I know this is an old question, but there's no need to add a gem dependency for this.
rack-timeout raises an exception; the 500 results from that exception being unhandled. To handle that exception and get a 503 or whatever else you might want, add:
config.action_dispatch.rescue_responses["Rack::Timeout::RequestTimeoutException"] = :service_unavailable
to your application.rb file.

How to diagnose why a Sinatra app is throwing NotFound in production but not in development?

I have a Sinatra app in production (running with Puma) that includes a not_found handler:
module MyApp
class Server
not_found do
[404, { 'Content-Type' => 'application/json' }, ['{"error":"not found"}']]
end
end
end
In development, this does what I expect and on missing pages I see a 404 with a JSON error message. However, in production I'm seeing a NotFound exception which triggers an Airbrake alert.
The stack trace is long, but the top line points here:
/gems/sinatra-1.4.5/lib/sinatra/base.rb:1021 in "route_missing"
Which is here:
https://github.com/sinatra/sinatra/blob/v1.4.5/lib/sinatra/base.rb#L1021 ,which does:
def route_missing
if #app
forward
else
raise NotFound
end
end
The comments in the Sinatra source say that the error is forwarded if your app is not middleware, otherwise it is raised. Yet somehow my expectation would be that my not_found handler should be called instead. It is being called in development. How can I best debug why it isn't in production?

Rendering 404 in sinatra if file not found

I have a basic sinatra app that renders files from a directory. What I'd like is returns 404 if page does not exist. Currently it raise 500 error.
get '/:page' do
erb :"pages/#{params[:page]}", layout: :"layouts/application"
end
Try this ;)
# 404 Error!
not_found do
status 404
erb :oops
end
Make yourself a 404 page with whatever name you like (mine is oops.erb, for example), and this should work just fine.
not_found is Sinatra's error-handling helper for grabbing error 500s and 404 not-founds that it returns. You can then change the HTTP status and corresponding view using it. Check out the documentation for all of Sinatra's error handler's: they're super useful!
You could do something like:
get '/:page' do
requested_erb = File.join(root, 'pages', params[:page])
pass unless File.exists?(requested_erb)
erb :"#{requested_erb}", :layout: :"layouts/application"
end
I haven't tested this, so there might be some issues with the above code, but that's the general idea in my head.

how to halt from inside stream block in sinatra?

I am trying to respond with a HTTP error code from my streaming block, but the web server throws an exception. what is the proper way to do it in this context?
/var/lib/gems/1.9.1/gems/sinatra-1.3.3/lib/sinatra/base.rb:803:in `throw':
uncaught throw :halt (ArgumentError)
my code:
require 'sinatra/base'
class App < Sinatra::Base
get '/' do
stream :keep_open do |out|
error 401
end
end
run! if app_file == $0
end
Based on my understanding of #stream(), the response Headers have already been sent. While you can continue streaming data (the body), and even close the connection, I don't think you can modify the header after they've already been sent. I'm digging through Sinatra YARD docs to verify, but I'm pretty sure that is your issue.

Resources