AWS Ruby Lambda function: undefined method `each_byte' for nil:NilClass - ruby

I deployed a Ruby application to AWS Lambda function. When I run a test, I get below the error:
...
Response
{
"errorMessage": "undefined method `each_byte' for nil:NilClass",
"errorType": "Function<NoMethodError>",
"stackTrace": [
"/var/task/response_handler.rb:32:in `receive_data'",
"/var/task/lambda_function.rb:8:in `lambda_handler'"
]
}
Function Logs
START RequestId: 8790420d1-1e34-2365-b62a-bcfc5789d50b Version: $LATEST
Critical exception from handler
{
"errorMessage": "undefined method `each_byte' for nil:NilClass",
"errorType": "Function<NoMethodError>",
"stackTrace": [
"/var/task/response_handler.rb:32:in `receive_data'",
"/var/task/lambda_function.rb:8:in `lambda_handler'"
]
}
...
Part of source code of response_handler is:
class ResponseHandler
attr_reader :data, :sqs
$messages_processed = 0
$datetime = DateTime.now
def initialize(data)
#data = data
#sqs = Aws::SQS::Client.new
end
def receive_data
data_arr = []
data.each_byte.map { |b| data_arr.push(b) }
data_hex = data.each_byte.map { |b| "%02X" % b }.join
EM.defer proc { process_lmu_message(data)}
end
...
I could not find the solution for this error.

Related

Ruby stub 3 class inside minitest - NoMethodError: undefined method allow_any_instance_of

I want to test my pure Ruby lambda handler which looks like this:
def lambda_handler(event:, context:)
payload = Parsers::IncomingEvents.new(event: event).call
ln_response = LN::Api.new(payload: payload).create_quiz
Responses::CreateQuiz.new(ln_response: ln_response, event: event).call
{ statusCode: 200, body: { message: event }.to_json }
end
To do so I'm using below minitest test:
require 'pry'
require 'minitest/autorun'
require 'active_support'
require_relative '../../src/Quiz_create/app'
module QuizCreate
class HandlerTest < ActiveSupport::TestCase
test 'lambda_handler' do
allow_any_instance_of(Parsers::IncomingEvents::CreateQuiz).to receive(:call)
allow_any_instance_of(LexisNexis::Api).to receive(:call)
allow_any_instance_of(Parsers::Responses::CreateQuiz).to receive(:call)
assert_response :success, lambda_handler(event: event, context: '')
end
def event
File.read('events/event.json')
end
end
end
But instead of expected results I'm getting an error:
NoMethodError: undefined method `allow_any_instance_of' for #QuizCreate::HandlerTest:0x00007fe4d61268e0

RSpec double/mock instance variable from initializer

I've got a class where in initializer I need to call instance variable from parsed params:
class PrintResults
include SortResults
attr_accessor :views_hash
def initialize(parser)
#parser = parser
#views_hash = parser.page_views
end
I want to test attributes accessors, I tried something below:
RSpec.describe PrintResults do
subject { described_class.new(views_hash) }
describe 'attributes accessors' do
let(:accessors) { double(page_views: { '/that_70s_show' => ['111.111.111.111'] }) }
it 'should have views hash' do
subject.views_hash = accessors
expect(subject.views_hash).to eq(['111.111.111.111'])
end
end
but I'm getting an error:
1) PrintResults attributes accessors should have views hash
Failure/Error: expect(subject.views_hash).to eq(['111.111.111.111'])
expected: ["111.111.111.111"]
got: #<Double (anonymous)>
(compared using ==)
Diff:
## -1 +1 ##
-["111.111.111.111"]
+#<Double (anonymous)>
You assign your test double directly to the attribute that is returned instead of using the initialize method.
Instead of
subject { described_class.new(views_hash) }
describe 'attributes accessors' do
let(:accessors) { double(page_views: { '/that_70s_show' => ['111.111.111.111'] }) }
it 'should have views hash' do
subject.views_hash = accessors
expect(subject.views_hash).to eq(['111.111.111.111'])
end
end
use
subject { described_class.new(parser) }
describe 'attributes accessors' do
let(:parser) { double(page_views: { '/that_70s_show' => ['111.111.111.111'] }) }
it 'should have views hash' do
expect(subject.views_hash).to eq('/that_70s_show' => ['111.111.111.111'])
end
end

API POST request returns 404 route not found

Rails 5.2.2.1
ruby 2.6.3p62
I'm writing an API endpoint that should accept a post request. I created the route:
namespace :api do
scope module: :v1, constraints: Example::ApiVersionConstraint.new(1) do
resources 'books', only: [:create]
end
end
bundle exec rails routes | grep books returns:
api_books POST /api/books(.:format) api/v1/books#create
app/controllers/api/v1/books_controller.rb:
class Api::V1::BooksController < Api::BaseController
attr_reader :book
def create
book = Book.build(title: 'test')
if book.save
render json: book
else
render json: { error: 'error' }, status: 400
end
end
end
server is running on port 3000 and when submitting a POST request to http://localhost:3000/api/books.json using Postman I get this response:
{
"errors": [
{
"code": "routing.not_found",
"status": 404,
"title": "Not found",
"message": "The path '/api/books' does not exist."
}
],
"request": ""
}
lib/example/api_version_constraint.rb:
module Example
class ApiVersionConstraint
def initialize(version)
#version = version
end
def matches?(request)
request.headers.fetch(:accept).include?("version=#{#version}")
rescue KeyError
false
end
end
end
why isn't the request finding the route?
Something is likely failing in ApiVersionConstraint. To troubleshoot you can do something like:
def matches?(request)
byebug
request.headers.fetch(:accept).include?("version=#{#version}")
rescue KeyError
false
end
Guessing it's a problem with how you're targeting the header, so something like this might work:
request&.headers&.fetch("Accept")&.include?("version=#{#version}")
Because you have a rescue clause, you'll never get the full error; only false, so you might try removing that and seeing if you get a more descriptive error.

Configure expect in rspec

I want to implement rspec with expect. I tried this:
RSpec:
describe WechatRequestBuilder do
let(:request_builder) { described_class.new(env: 'test_env') }
let(:trx_types) { ['wechat'] }
let(:trx_type) { 'wechat' }
let(:gateway) { 'wechat' }
let(:currency) { 'CNY' }
let(:base_params) { request_builder.send(:base_params) }
it_behaves_like 'request builder', true
context '#submit!' do
it "sends test transactions" do
allow(request_builder).to receive(:process_trx).with(trx_types, gateway)
binding.pry
request_builder.submit!
expect(request_builder.submit!).to receive(:process_trx).with(trx_types, gateway)
end
end
end
Request modifier:
class RequestModifier
def get_trx_type(request_body)
doc = Nokogiri::XML(request_body)
doc.search("transaction_type").first.text
end
end
I tried to find some object with binding.pry but without a luck:
[1] pry(#<RSpec::ExampleGroups::WechatRequestBuilder::Submit>)> request_builder
=> #<WechatRequestBuilder:0x007ffc1af4fd80 #env="test_env", #request_modifier=#<RequestModifier:0x007ffc1af4fd30>>
Can you give e some example based on the above code what should I configure as 'expect'? Currently I get:
(nil).process_trx(["wechat"], "wechat")
expected: 1 time with arguments: (["wechat"], "wechat")
received: 0 times

undefined method `to_sym' when yaml file is stubbed

I have this rspec task which I would like to implement with stubbed config file:
let(:request_builder) { described_class.new(env: nil) }
let(:trx_types) { ['davivienda'] }
let(:trx_type) { 'davivienda' }
let(:gateway) { 'girogate' }
let(:currency) { 'USD' }
let(:base_params) { request_builder.send(:base_params) }
before(:each) { allow(request_builder).to receive(:currency).and_return('USD') }
let(:yaml_file) { YAML::load(File.read(File.join('spec', 'fixtures', 'yaml', 'env.yml'))) }
let(:config) { yaml_file['SOF_DEV'] }
context '#submit!' do
it "sends test transactions" do
allow(request_builder).to receive(config).and_return(config)
request_builder.submit!
PAYMENT_TYPE_WITH_BASE_PARAMS.each do |x|
expect(request_builder).te receive(:process_trx).with(factory(x), :gateway, :base_params)
end
end
end
I get error at this line:
allow(request_builder).to receive(config).and_return(config)
NoMethodError:
undefined method `to_sym' for #<Hash:0x007f86484eb440>
Do you know how I can fix this issue?
You've passed in config rather than :config to the expected call.
It should be:
allow(request_builder)
.to receive(:config)
.and_return(config)

Resources