Ruby: how to test against an exception - ruby-on-rails

I'm new to Ruby, I would like to write a spec against logger expection using allow. Please help, thank you.
Current spec
it 'raises exception fetching auditables' do
allow(NightLiaison::HttpConnection.open).to receive(:get).and_raise(StandardError)
expect { described_class.fetch_auditables }.to raise_error('Fetching auditables raised an exception')
end
end
Method:
def self.fetch_auditables
HttpConnection.open.get AppConfig.api.nightliaison.fetch_auditables
rescue => e
LOGGER.error('Fetching auditables raised an exception', exception: e)
Faraday::Response.new
end
Error Message:
got #<WebMock::NetConnectNotAllowedError: Real HTTP connections are disabled. Unregistered request: GET h... => 200, :body => "", :headers => {})

Looks like it fails when it tries open - if you mock that too, it could work. Try something like:
it 'raises exception fetching auditables' do
open_mock = double
allow(open_mock).to receive(:get).and_raise(StandardError)
allow(NightLiaison::HttpConnection).to receive(:open).and_return(open_mock)
expect { described_class.fetch_auditables }.to raise_error('Fetching auditables raised an exception')
end

Try:
allow(NightLiaison::HttpConnection).to receive_message_chain(:open, :get) { raise StandardError }

Related

test coverage for rescue blocks in rspec

I am trying to get coverage on the following sections of code (from begin to end)in my attached spec where
def process_request(data)
agents = agent_emails(data)
begin
ej = EmailerJob.new(agents: agents, data: data)
CommonLogger.input_log(log_obj,"Sending Lead email to #{agents}")
ej.deliver_emails
rescue Timeout::Error => error
CommonLogger.input_log(log_obj,"#{error}","error")
raise error
rescue StandardError => error
Rails.logger.error "StandardError Handling for #{agents}"
CommonLogger.input_log(log_obj,"#{error}","error")
rescue Exception => error
Rails.logger.error "Exception Handling for #{agents}"
CommonLogger.input_log(log_obj,"#{error}","error")
raise error
end
end
coverage report:
Can somebody please help me how can i cover all rescue sections?
Rspec: 3.12.0

How to catch a Rack RangeError in Rails 6

I have a Rails 6 app to which users can upload CSV files. Rails/Rack imposes a limit in the number of params that can be included in a request, and I've set this to a size larger than likely submissions to my app. However, I would like to return a friendly response if a too-large file is uploaded.
It looks like I need to add some custom middleware, to catch and rescue the error, but I can't get the code to work - the basic error is still raised without my rescue block being called.
The error from the server is:
Rack app error handling request { POST /[PATH_TO]/datasets }
#<RangeError: exceeded available parameter key space>
The code in my app/middleware/catch_errors.rb file is basically taken from a previous SO answer, where someone was catching ActionDispatch::ParamsParser::ParseError in JSON, but with my own code in the rescue block (which I realise may not work properly in this context, but that's not the issue right now):
class CatchErrors
def initialize(_app)
#app = _app
end
def call(_env)
begin
#app.call(_env)
rescue RangeError => _error
_error_output = "There were too many fields in the data you submitted: #{_error}"
if env['HTTP_ACCEPT'] =~ /application\/html/
Rails.logger.error("Caught RangeError: #{_error}")
flash[:error_title] = 'Too many fields in your data'
flash[:error_detail1] = _error_output
render 'static_pages/error', status: :bad_request
elsif env['HTTP_ACCEPT'] =~ /application\/json/
return [
:bad_request, { "Content-Type" => "application/json" },
[ { status: :bad_request, error: _error_output }.to_json ]
]
else
raise _error
end
end
end
end
I'm loading it in config.application.rb like this:
require_relative '../app/middleware/catch_errors'
...
config.middleware.use CatchErrors
I'm resetting the size limit for testing in app/initializers/rack.rb like this:
if Rack::Utils.respond_to?("key_space_limit=")
Rack::Utils.key_space_limit = 1
end
Any help gratefully received!
First, execute command to see all middlewares:
bin/rails middleware
config.middleware.use place your middleware at the bottom of the middleware stack. Because of that it can not catch error. Try to place it at the top:
config.middleware.insert_before 0, CatchErrors
Another point to mention, may be you will need to config.middleware.move_after or even config.middleware.delete some middleware. For instance, while tinkering I needed to place:
config.middleware.move_after CatchErrors, Rack::MiniProfiler

getting httparty undefined method `code' for #<Hash:0x007ff3625a4800> in rspec

I am writing specs for my first gem. But i am stuck with this weird error.
code for my rspec is
describe '#success' do
let(:resp) { {"TwilioResponse"=>{"SMSMessage"=>{"Sid"=>"0d1c0cbfb2b5e8f97dddb4479bdbbc6a", "AccountSid"=>"exotel_sid", "From"=>"/exotel_sid", "To"=>"1234", "DateCreated"=>"2016-07-18 15:35:29", "DateUpdated"=>"2016-07-18 15:35:29", "DateSent"=>nil, "Body"=>"test sms", "Direction"=>"outbound-api", "Uri"=>"/v1/Accounts/exotel_sid/Sms/Messages/0d1c0cbfb2b5e8f97dddb4479bdbbc6a", "ApiVersion"=>nil, "Price"=>nil, "Status"=>"queued"}}} }
before{ allow(Generator::Exotel).to receive(:post).with("/#{Generator::configuration.sid}/Sms/send",
{:body => {:To => 1234, :Body => 'test sms'},:basic_auth=>{:username=>"#{Generator::configuration.sid}", :password=>"#{Generator::configuration.token}"}}).and_return(resp) }
it 'returns response object' do
response = Generator::Exotel.send(:to => 1234, :body => "test sms")
expect(response).to eq ({"Status"=>200, "Message"=>"Success"})
end
end
when i run rspec i am getting this error
NoMethodError:
undefined method `code' for #<Hash:0x007ff3625a4800>
This is where my response.code is being called
def handle_response(response)
response_base = response['TwilioResponse']
if response_base.include?('RestException')
response_base['RestException']
else
{"Status" => response.code, "Message" => "Success" }
end
end
I know httparty creates a response object for request and returns response code. But i am not getting how do i create a dummy response_code
so that my test case pass. It's nearly 2 days since i am stuck here. Anyone help please. I am really new to ruby and for first time writing spec. Any help will be appreciated.
Update - result for response.inspect
> Generator::Exotel.send(:to => 9030435595, :body => 'jsdhgjkdfg')
it returns following response
> #<HTTParty::Response:0x7fb8c02f93d0 parsed_response={"TwilioResponse"=>{"SMSMessage"=>{"Sid"=>"d6ee0650072c82941ad2f06746d14ab4", "AccountSid"=>"sinscary", "From"=>"/sinscary", "To"=>"9030435595", "DateCreated"=>"2016-07-21 19:56:07", "DateUpdated"=>"2016-07-21 19:56:07", "DateSent"=>nil, "Body"=>"jsdhgjkdfg", "Direction"=>"outbound-api", "Uri"=>"/v1/Accounts/sinscary/Sms/Messages/d6ee0650072c82941ad2f06746d14ab4", "ApiVersion"=>nil, "Price"=>nil, "Status"=>"queued"}}}, #response=#<Net::HTTPOK 200 OK readbody=true>, #headers={"content-type"=>["application/xml"], "date"=>["Thu, 21 Jul 2016 14:26:07 GMT"], "server"=>["Apache/2.2.29 (Amazon)"], "x-powered-by"=>["PHP/5.3.28"], "content-length"=>["542"], "connection"=>["Close"]}>
OK, you are mocking an HTTParty::Response. One way would be to mock it directly with only code and parsed_response:
let(:resp) do
Struct.new(:code, :parsed_response).new(200, {"TwilioResponse"=>...})
end
Another way would be to instantiate a real HTTParty::Response with:
let(:resp) do
HTTParty::Response.new(
nil,
Struct.new(:code, :parsed_response)
.new(200, {"TwilioResponse"=>...}), -> { ... }
)
end
I would go with the first approach. Please note, that you probably will need to change in handle_response:
response_base = response['TwilioResponse']
to
response_base = response.parsed_response['TwilioResponse']

RSpec: force Net::SFTP::StatusException and validate rescue

I'm trying to force an Net::SFTP::StatusException error in my spec and then validate that my code traps it.
Code:
def process_SFTP(username, password, csvfile)
begin
mySftpWrapper.new
mySftpWrapper.process_CSV_file(csvfile)
rescue RuntimeError => other_problem
logger.info(other_problem.message)
rescue Net::SFTP::StatusException => sftp_problem
logger.info(sftp_problem.message)
end
end
RSpec:
let(:wrapper) { mySftpWrapper.new }
before(:all) do
#wrapper_mock = double('mySftpWrapper')
mySftpWrapper.stub(:new).and_return(#wrapper_mock)
#logger_mock = double('ActiveSupport::BufferedLogger')
end
it "should trap a Net::SFTP::StatusException" do
sftp_response = Object.new
def sftp_response.code; code = 2 end
def sftp_response.message; message = "no such file" end
# Force exception here
#wrapper_mock.stub(:process_SFTP).with("username", "password", "nonexistentfile").and_raise(Net::SFTP::StatusException.new(sftp_response))
# Verify that logger.info received the forced error
#logger_mock.stub(:info).should_receive(/no such file/)
wrapper.process_SFTP("date", "username", "password", "nonexistentfile")
end
However, the statement I use to generate the Net::SFTP::StatusException doesn't throw the correct exception ("Net::SFTP::StatusException"). Instead it throws #<Net::SFTP::StatusException: Net::SFTP::StatusException>
How do I force the correct StatusException?
Any ideas are much appreciated!
As it turns out, the spec example is throwing exactly the correct Exception. The problem is that the Net::SFTP::StatusException is subclassed from RuntimeError:
net-sftp-2.0.5/lib/net/sftp/errors.rb:
module Net; module SFTP
# The base exception class for the SFTP system.
class Exception < RuntimeError; end
# A exception class for reporting a non-success result of an operation.
class StatusException < Net::SFTP::Exception
and the Net::SFTP::StatusException was getting thrown, but it was getting trapped by the RuntimeError clause before reaching the StatusException clause. Exactly what a spec is for!

How to check for specific rescue clause for error handling in Rails 3.x?

I have the following code:
begin
site = RedirectFollower.new(url).resolve
rescue => e
puts e.to_s
return false
end
Which throws errors like:
the scheme http does not accept registry part: www.officedepot.com;
the scheme http does not accept registry part: ww2.google.com/something;
Operation timed out - connect(2)
How can I add in another rescue for all errors that are like the scheme http does not accept registry part?
Since I want to do something other than just printing the error and returning false in that case.
That depends.
I see the three exception descriptions are different. Are the Exception types different as well?
If So you could write your code like this:
begin
site = RedirectFollower.new(url).resolve
rescue ExceptionType1 => e
#do something with exception that throws 'scheme http does not...'
else
#do something with other exceptions
end
If the exception types are the same then you'll still have a single rescue block but will decide what to do based on a regular expression. Perhaps something like:
begin
site = RedirectFollower.new(url).resolve
rescue Exception => e
if e.message =~ /the scheme http does not accept registry part/
#do something with it
end
end
Does this help?
Check what is exception class in case of 'the scheme http does not accept registry part' ( you can do this by puts e.class). I assume that this will be other than 'Operation timed out - connect(2)'
then:
begin
.
rescue YourExceptionClass => e
.
rescue => e
.
end
Important Note: Rescue with wildcard, defaults to StandardError. It will not rescue every error.
For example, SignalException: SIGTERMwill not be rescued with rescue => error. You will have to specifically use rescue SignalException => e.

Resources