Rails App with Sinatra engine - How to avoid rails errors? - ruby-on-rails

Problem: When running specs the output is very confusing, instead of saying where the error lies it just throws misleading errors
This is inside the rails lib folder, and it's mounted on the routes.rb
# lib/engines/users/app.rb
module Engines
module Users
class App < Sinatra::Base
get '/api/v1/users/me' do
raise 'runtime error here'
end
get '/api/v1/another-route' do
# something here
status 200
end
end
end
end
The spec file looks something like this:
it 'returns a 200' do
get '/api/v1/users/me', auth_attributes
expect(last_response.body).to eq 'something' # added to clarify my point, it's not the response status that I care of.
expect(last_response.status).to be 200
end
error:
Failure/Error: expect(last_response.status).to be 200
expected #<Fixnum:401> => 200
got #<Fixnum:1001> => 500
Compared using equal?, which compares object identity,
but expected and actual are not the same object. Use
`expect(actual).to eq(expected)` if you don't care about
object identity in this example.
expected error:
RuntimeError:
runtime error here
Another route also fails:
it 'something' do
get '/api/v1/another-route', auth_attributes
expect(last_response.status).to be 401
json = JSON.parse(last_response.body).with_indifferent_access
expect(json[:message]).to eql "You have been revoked access."
end
error: Prints a massive html output which I believe is the rails backtrace html output
expected error: none as this endpoint doesn't raise an error
My question is if there's a way to:
Stop rails from dealing with this, so it gives the actual output
Avoid the entire engine to fail because one route raise exception
I believe that by solving the first point, the second one gets fixed too.
Thank you for your time

In order to solve my problem I've discovered that on the spec_helper the ENV['RACK_ENV'] was not being set, setting it to test resolves the problem and throws the exception I need in order to debug my code.
This happens because https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1832
set :show_exceptions, Proc.new { development? }
development? returned true when in fact should be false (needed the RACK_ENV set to test)
Now I get the correct output.

Related

RSpec wrong with MiniMagick convert file only gitlab ci/cd (not in env development)

class **ConverterFile**
attr_accessor :old_file
SUPPORT_IMAGE_FORMAT = %w[png jpg jpeg pdf].freeze
def initialize(old_file)
#old_file = old_file
end
def to_image_type(file_format)
raise 'format not support' if file_format.blank? || SUPPORT_IMAGE_FORMAT.exclude?(file_format)
return old_file if File.extname(#old_file) == ".#{file_format}"
converted_file = MiniMagick::Image.open(#old_file.path)
converted_file.format(file_format)
File.open(converted_file.path)
rescue StandardError => e
nil
end
end
describe '#to_image_type' do
let(:png_file) { File.open(Rails.root.join('spec/support/files/logo.png')) }
context 'when convert to jpg file' do
it 'convert png file to jpg successfuly' do
new_file = described_class.new(png_file).to_image_type('jpg')
expect(File.extname(new_file)).to eq('.jpg')
end
end
end
error-in-gitlab-ci-cd
I'am confusing because i' try run spec in env dev local is pass but gitlab ci/cd error every times. I think error is about reference file missing not sure.
The error says that File.extname is being called with a nil argument:
File.extname(nil)
#=> TypeError: no implicit conversion of nil into String
This means new_file must be nil.
This means described_class.new(png_file).to_image_type('jpg') must be returning nil.
Why is this happening? Well, it's hard for me to say for sure without taking a closer look at the CI setup, but I am highly suspicious of this part of the code:
rescue StandardError => e
nil
end
Your method is silently swallowing errors, and returning nil. That doesn't seem like a good idea here in general, and it's probably hiding the true cause of the test failure!
My suspicion is that you have not committed the file 'spec/support/files/logo.png' into source control. So the test passes locally, but fails on CI where this file does not exist.
I think an exception is being raised when the non-existed file gets opened, but you're capturing the exception and returning nil -- which results in this more confusing test failure message.

Is there a list of JSON parse error codes?

I'm trying to provide a good experience to users that are using JSON and the parser is on the backend (Ruby).
Most of the time, when you get a badly formatted JSON payload the error is of the format XXX unexpected token at '<entire payload here>'. That's not very user-friendly nor practical.
My question is: Is there a list of the XXX error codes that could help create better error messages that could be understood by beginners and not-really-tech-people?
Thanks!
XXX in this kind of errors is not a special code of the error. It is just a line number from the file where this error was raised. For example, for Ruby 2.5.1 you'll get JSON::ParserError (765: unexpected token at https://github.com/ruby/ruby/blob/v2_5_1/ext/json/parser/parser.rl#L765
You can find a list in the documentation for the module.
Think this covers it:
JSON::JSONError
JSON::GeneratorError
JSON::GenericObject
# The base exception for JSON errors.
JSON::MissingUnicodeSupport
# This exception is raised if the required unicode support is missing on the system. Usually this means that the iconv library is not installed.
JSON::NestingError
# This exception is raised if the nesting of parsed data structures is too deep.
JSON::ParserError
# This exception is raised if a parser error occurs.
JSON::UnparserError
# This exception is raised if a generator or unparser error occurs.
JSON::JSONError is the parent class, so you can rescue from that and provide per-error-class messages as needed.
I feel it's worth noting that in my experience the vast majority of errors relating to JSON are of the class JSON::ParserError. Another common issue worth considering is getting ArgumentError if nil is passed as an argument.
As an example of how this could be used, you could work with something like the following:
begin
JSON.parse(your_json)
rescue JSON::JSONError, ArgumentError => e
{ error: I18n.t(e.to_s) } # <- or whatever you want to do per error
end
Hope that helps - let me know how you get on :)

Why does the Rails.logger write to the same log file in development and test?

I have the following model test:
describe 'Checking for errors' do
it 'should check for any jobs that have errors and log them' do
logger = Logger.new('log/go_job_errors_test.log')
code_location = create(:code_location_with_best_code_set)
code_location.jobs << create(:complete_job, status: 3, exception: 'I failed to complete')
CodeLocationJobFeeder.create(code_location_id: code_location.id, url: code_location.repository.url, status: 2)
CodeLocationJobFeeder.check_for_errors(1)
logger.expects(:info).with("I failed to complete")
end
With the following model code:
def check_for_errors(amount)
processed.limit(amount).each do |code_location_job_feeder|
code_location = CodeLocation.includes(:jobs).find(code_location_job_feeder.code_location_id)
log_error(code_location) unless code_location.jobs.last.status != 3
end
end
private
def log_error(code_location)
logger = Logger.new('log/go_job_errors.log')
failed_job = code_location.jobs.last
logger.info do
"Job #{failed_job.id} with code location: #{code_location.id} failed. Exception: #{failed_job.exception}"
end
end
The gist of the test is that when I execute CodeLocationJobFeeder.check_for_errors I'll have a separate log file that will tell me all the info that I want concerning some errors. This works fine in development and I get the file that I want. However when I run the test, I get output in both log/go_job_errors_test.log and log/go_job_errors.log with the following output:
log/go_job_errors.log
[2017-06-28T18:23:46.164141 #29604] INFO -- : Job 40 with code location: 93 failed. Exception: I failed to complete
This is the content that I want but in the wrong file. Here is the second file:
log/go_job_error_test.log
# Logfile created on 2017-06-28 18:40:59 +0000 by logger.rb/47272
The correct file with the wrong content.
I've been trying to apply this s.o. answer Logger test but it doesn't seem to be working too great. Can someone help point out what I'm doing wrong?
This line "Logger.new('log/go_job_errors.log')" in the model instructs to log model errors to this file 'log/go_job_errors.log'. Irrespective of environment, the model errors are always logged here 'log/go_job_errors.log'
In your tests, you start with this line 'Logger.new('log/go_job_errors_test.log')', this line creates a new log file. And when your test calls the model, the model calls 'log_error(code_location)', but that method only logs to 'log/go_job_errors.log'.

upgrading 3.12 to 4, run rails s, get stack level too deep error in local_cache_middleware

Used rake rails:update, meticulously updated overwritten files, and have my rspec specs running green. But when I run rails s I hit this:
Unexpected error while processing request: stack level too deep
/Users/Alex/.rvm/gems/ruby-2.0.0-p451/gems/activesupport-4.1.4/lib/active_support/cache/strategy/local_cache_middleware.rb:33
Specifically it is crapping out at response = #app.call(env) (line 26) in the above cited file.
I'm working through checklists to see if I might have missed a configuration setting somewhere. Can anyone give me a clue?
So, first thing I did was get a full backtrace out of the exception by adding:
rescue Exception => e
puts e.backtrace
LocalCacheRegistry.set_cache_for(local_cache_key, nil)
raise
end
Which then revealed one critical line before the cache middleware one I saw before:
/Users/Alex/.rvm/gems/ruby-2.0.0-p451/gems/activesupport-4.1.4/lib/active_support/logger.rb:38
Unexpected error while processing request: stack level too deep
/Users/Alex/.rvm/gems/ruby-2.0.0-p451/gems/activesupport-4.1.4/lib/active_support/cache/strategy/local_cache_middleware.rb:35
I jumped into the listed line which looked like this:
define_method(:level=) do |level|
logger.level = level
super(level)
end
Then searched the rest of my repo to see where I was touching logger.level. (If I hadn't been able to find the call that way, I would've used Kernel#caller.) Ahah, I discover: config/initializers/quiet_assets.rb, hmm what is this? Looks like a monkey-patch I put in an initializer ages ago:
# taken from https://stackoverflow.com/questions/6312448/how-to-disable-logging-of-asset-pipeline-sprockets-messages-in-rails-3-1
if Rails.env.development?
Rails.application.assets.logger = Logger.new('/dev/null')
Rails::Rack::Logger.class_eval do
def call_with_quiet_assets(env)
previous_level = Rails.logger.level
Rails.logger.level = Logger::ERROR if env['PATH_INFO'] =~ %r{^/assets/}
call_without_quiet_assets(env)
ensure
Rails.logger.level = previous_level
end
alias_method_chain :call, :quiet_assets
end
end
When I commented this out, poof, my error was gone and I was able to load up a page in browser. Now I've deleted the initializer and am good to go. :) For those that used How to disable logging of asset pipeline (sprockets) messages in Rails 3.1?, make sure to remove it when you upgrade!

Setting more than one cookie in integration test causes NoMethodError after upgrading rails 2.3

This all worked fine in rails 2.3.5, but when a contractor firm upgraded directly to 2.3.14 suddenly all the integration tests were saying:
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]
I have a before_filter on my ApplicationController that sets a bunch of cookies for some javascript to use, and I found that if I comment out all but one of the lines that sets cookie values, it works fine, and it doesn't matter which line I leave in.
before_filter :set_cookies
def set_cookies
cookies['logged_in'] = (logged_in ? 'y' : 'n')
cookies['gets_premium'] = (gets_premium ? 'y' : 'n')
cookies['is_admin'] = (is_admin ? 'y' : 'n')
end
If only one of these lines is active, everything is fine in the integration test, otherwise I get the error above. For example, consider the following test / response:
test "foo" do
get '/'
end
$ ruby -I"lib:test" test/integration/foo_test.rb -n test_foo -v
Loaded suite test/integration/foo_test
Started
test_foo(FooTest): E
Finished in 5.112648 seconds.
1) Error:
test_foo(FooTest):
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]
test/integration/foo_test.rb:269:in `test_foo'
1 tests, 0 assertions, 0 failures, 1 errors
But if any two of those cookie setting lines are commented out, I get:
$ ruby -I"lib:test" test/integration/foo_test.rb -n test_foo -v
Loaded suite test/integration/foo_test
Started
test_foo(FooTest): .
Finished in 1.780388 seconds.
1 tests, 0 assertions, 0 failures, 0 errors
The website running in development and production mode works fine - this is just a matter of getting the tests passing. Also, with debugging output I have verified that the error does not get thrown in the method where the cookies get set, that all executes fine, it's somewhere later that the error happens (but the backtrace doesn't tell me where)
This turned out to be a bug in how rack rack writes cookies to the client along with the session cookie. Rack was including double newlines and omitting semi-colons.
Browsers like firefox can handle mildly malformed cookie data, but the integration test client couldn't.
To fix this I had to rewrite the cookie header before sending it to the client.
In environment.rb:
require 'rack_rails_cookie_header_hack'
And in lib/rack_rails_cookie_header_hack.rb:
class RackRailsCookieHeaderHack
def initialize(app)
#app = app
end
def call(env)
status, headers, body = #app.call(env)
if headers['Set-Cookie']
cookies = headers['Set-Cookie']
cookies = cookies.split("\n") if is_str = cookies.is_a?(String)
if cookies.respond_to?(:collect!)
cookies.collect! { |h| h.strip }
cookies.delete_if { |h| h.empty? }
cookies.collect! { |h| h.include?(';') ? h : h + ';' }
end
headers['Set-Cookie'] = is_str ? cookies.join("\n").strip : cookies
end
[status, headers, body]
end
end
Sorry the sources aren't articulated, I actually fixed this awhile ago and came across this questions and figured I'd post my patch.
L0ne's answer works for me, but you also need to include this - it can go at the bottom of lib/rack_rails_cookie_header_hack.rb, providing you're requiring it at the bottom of your environment.rb file - ie after the Rails::Initializer has run:
ActionController::Dispatcher.middleware.insert_before(ActionController::Base.session_store, RackRailsCookieHeaderHack)
Old forgotten issues...
I haven't tested Lone's fix but he has correctly identified the problem. If you catch the exception and print using exception.backtrace, you'll see that the problem is caused by
gems/actionpack/lib/action_controller/integration.rb:329
The offending code is this:
cookies.each do |cookie|
name, value = cookie.match(/^([^=]*)=([^;]*);/)[1,2]
#cookies[name] = value
end
If you're like me, and you're only interested in some super quick integration tests, and don't care too much about future maintainability (since it's rails 2), then you can just add a conditional filter in that method
cookies.each do |cookie|
unless cookie.blank?
name, value = cookie.match(/^([^=]*)=([^;]*);/)[1,2]
#cookies[name] = value
end
end
and problem solved

Resources