How to access Parent imported functions from Module - testing

I'm trying to create a test helper for testing an app that uses the Maru Framework. This is a simplified version of what I'm trying to achieve:
defmodule App.ExtendedMaru do
#moduledoc false
defmacro __using__(opts) do
quote do
use Maru.Test, unquote(opts)
end
end
def post_body(url, body) do
build_conn()
|> Plug.Conn.put_req_header("content-type", "application/json")
|> put_body_or_params(Poison.encode! body)
|> post(url)
end
end
The issues are with the build_conn/0 and post/2 functions. build_conn/0 is defined in Maru.Test and can thus be reached with import Maru.Test inside this module.
However, post/2 is a private function defined inside the __using__ macro for Maru.Test. So, it is present in the module that uses this one, but it's not available to post_body/2. I can't just use Maru.Test here as I'm required to pass the opts and haven't found a way to do so.
Is it possible to access the post/2 function that should be defined in the module that's including this one?
EDIT: How the code ended up:
defmodule Legacy.ExtendedMaru do
#moduledoc """
Adds a few extra function helpers for testing using the Maru framework. Use
it as you would Maru.Test, ie:
`use Legacy.ExtendedMaru, for: An.Api.Module`
"""
defmacro __using__(opts) do
quote do
use Maru.Test, unquote(opts)
unquote(add_post_body())
end
end
defp add_post_body() do
quote do
#doc """
Makes a POST request with the given body. Correctly encodes the body in the
requested format and sets Content-Type headers.
## Parameters
- url: The URL for the POST request
- body: The body to send on the request
- opts: For customizing function behaviour:
- format: What format to send the body in. Defaults to 'json'.
"""
#spec post_body(String.t, map(), keyword(String.t)) :: Plug.Conn.t
def post_body(url, body, opts \\ []) do
format = opts[:format] || "json"
build_conn()
|> add_content(body, format)
|> post(url)
end
def add_content(conn, body, "json") do
Plug.Conn.put_req_header(conn, "content-type", "application/json")
|> put_body_or_params(Poison.encode! body)
end
end
end
end

Your problem arises from two separate things:
The post_body method is private, so you can't call it outside of your Module.
The post_body method is not in the __using__ macro so it's not available to any of the other modules that use it.
There are two simple solutions to this:
Move the post_body method inside the __using__ macro. Once you do this, all modules that use it, will be able to call post_body except the original module.
(or) Make the post_body method public and call defdelegate on it inside __using__. This way you'll be able to call it in all modules including the original one.

Related

Falcon - Difference in stream type between unittests and actual API on post

I'm trying to write unittests for my falcon api, and I encountered a really weird issue when I tried reading the body I added to the unittests.
This is my unittest:
class TestDetectionApi(DetectionApiSetUp):
def test_valid_detection(self):
headers = {"Content-Type": "application/x-www-form-urlencoded"}
body = {'test': 'test'}
detection_result = self.simulate_post('/environments/e6ce2a50-f68f-4a7a-8562-ca50822b805d/detectionEvaluations',
body=urlencode(body), headers=headers)
self.assertEqual(detection_result.json, None)
and this is the part in my API that reads the body:
def _get_request_body(request: falcon.Request) -> dict:
request_stream = request.stream.read()
request_body = json.loads(request_stream)
validate(request_body, REQUEST_VALIDATION_SCHEMA)
return request_body
Now for the weird part, my function for reading the body is working without any issue when I run the API, but when I run the unittests the stream type seems to be different which affect the reading of it.
The stream type when running the API is gunicorn.http.body.Body and using unittests: wsgiref.validate.InputWrapper.
So when reading the body from the api all I need to do it request.stream.read() but when using the unittests I need to do request.stream.input.read() which is pretty annoying since I need to change my original code to work with both cases and I don't want to do it.
Is there a way to fix this issue? Thanks!!
It seems like issue was with how I read it. instead of using stream I used bounded_stream which seemed to work, also I removed the headers and just decoded my body.
my unittest:
class TestDetectionApi(DetectionApiSetUp):
def test_valid_detection(self):
body = '''{'test': 'test'}'''
detection_result = self.simulate_post('/environments/e6ce2a50-f68f-4a7a-8562-ca50822b805d/detectionEvaluations',
body=body.encode(), headers=headers)
self.assertEqual(detection_result.json, None)
how I read it:
def _get_request_body(request: falcon.Request) -> dict:
request_stream = request.bounded_stream.read()
request_body = json.loads(request_stream)
validate(request_body, REQUEST_VALIDATION_SCHEMA)
return request_body

How to use API to invoke Lambda function

Im trying to setup an API which will invoke a Lambda function. The function is written with Pyhton.
I have setup a URL Query parameter and also a mapping template.
When using the api URL I have added parameters at the end of the URL so I can invoke it
To get this working I believe I need to somehow add these parameters into my python script. Can anyone tell me how this is done?
Thanks
Check my code below
https://github.com/mmakadiya/aws_lambda-API_gateway-Import-XML-data
You can update the lambda function with below code
import JSON
def lambda_handler(event, context):
print("####################################")
print(event)
print("####################################")
# TODO implement
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
When you will trigger a POST request like below
https://gjtf9q4422.execute-api.ap-south-1.amazonaws.com/Dev?autooff=yes?autoon=no?testparam=haha
the "event" will print the query string like this. Simply you can grab it from the "event' parameter as well.
query_string

How to test a helper Grok view that makes a redirect

I have a content type that needs to be modified in some way after calling a helper Grok view that checks some condition, makes some changes, sets a message and redirects to the original object.
my helper view only has a render method and I want to write some tests for it but I have no idea how to handle this.
I would like to check for an error message when some condition is not met, and for an info message when everything goes fine.
my code looks like this:
class MyHelperView(grok.View):
grok.context(IMyType)
grok.layer(IMyLayer)
grok.name('helper-view')
grok.require('my.permission')
def render(self):
variable = self.request.form.get('variable', None)
if not variable:
msg = _(u'Required input is missing.')
api.portal.show_message(message=msg, request=self.request, type='error')
else:
do_something()
msg = _(u'Information processed.')
api.portal.show_message(message=msg, request=self.request)
self.request.response.redirect(self.context.absolute_url())
when I call the view obviously I ended with a None object, as the view returns nothing. I don't know where to look for messages... request? response? any hint?
I would avoid using transaction commits in test code. The test framework is specifically designed to roll back the transactions at the end of each test. Your setUp override goes against this.
To check status messages in a unit test you should be able to do something like:
from Products.statusmessages.interfaces import IStatusMessage
IStatusMessage(request).show()
This is an adapter that adapts the request.
I ended up with test with a layer based on FunctionalTesting:
....
from plone.app.testing import TEST_USER_NAME
from plone.app.testing import TEST_USER_PASSWORD
from plone.testing.z2 import Browser
....
import transaction
...
class HelperViewTestCase(unittest.TestCase):
layer = FUNCTIONAL_TESTING
def setUp(self):
self.app = self.layer['app']
self.portal = self.layer['portal']
self.request = self.layer['request']
directlyProvides(self.request, IMyLayer)
with api.env.adopt_roles(['Manager']):
self.foo = api.content.create(self.portal, 'MyType', 'foo')
transaction.commit()
def test_response(self):
browser = Browser(self.app)
browser.handleErrors = False
browser.addHeader(
'Authorization',
'Basic {0}:{1}'.format(TEST_USER_NAME, TEST_USER_PASSWORD)
)
browser.open(self.foo.absolute_url())
browser.getControl('Do Something').click()
self.assertIn(
'Required input is missing.', browser.contents)
two things you need to check that make me spent some time debugging:
you must use transaction.commit() to reflect object creation on the ZODB
you must add an authorization header before trying to open the page
everything else is working.

Rails 3 - Pass a parameter to custom validation method

I am looking to pass a value to a custom validation. I have done the following as a test:
validate :print_out, :parameter1 => 'Hello'
With this:
def print_out (input="blank")
puts input
end
When creating an object or saving an object, the output is 'blank.' However, if called directly:
object.print_out "Test"
Test is instead outputted. The question is, why is my parameter not passing properly?
Inside the 'config\initializers\' directory, you can create your own validations. As an example, let's create a validation 'validates_obj_length.' Not a very useful validation, but an acceptable example:
Create the file 'obj_length_validator.rb' within the 'config\intializers\' directory.
ActiveRecord::Base.class_eval do
def self.validates_obj_length(*attr_names)
options = attr_names.extract_options!
validates_each(attr_names, options) do |record, attribute, value|
record.errors[attribute] << "Error: Length must be " + options[:length].to_s unless value.length == options[:length]
end
end
end
Once you have this, you can use the very clean:
validates_obj_length :content, :length => 5
Basically, we reopen ActiveRecord::Base class and implement a new sub-validation. We use the splat (*) operator to accept an array of arguments. We then extract out the hash of options into our 'options' variable. Finally we implement our validation(s). This allows the validation to be used with any model anytime and stay DRY!
You could try
validate do |object_name|
object_name.print_out "Hello"
end
Instead of your validate :print_out, :parameter1 => 'Hello'.

What am I doing wrong with this rspec helper test?

All I'm trying to do is spec how a one line helper method for a view should behave, but I'm not sure what kind of mock object, (if any) I should be creating if I'm working in Rails.
Here's the code for events_helper.rb:
module EventsHelper
def filter_check_button_path
params[:filter].blank? ? '/images/buttons/bt_search_for_events.gif' : '/images/buttons/bt_refine_this_search.gif'
end
end
And here's my spec code, in events_helper_spec.rb:
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe EventsHelper do
#Delete this example and add some real ones or delete this file
it "should be included in the object returned by #helper" do
included_modules = (class << helper; self; end).send :included_modules
included_modules.should include(EventsHelper)
end
it "should return the 'refine image search' button if a search has been run" do
# mock up params hash
params = {}
params[:filter] = true
# create an instance of the class that should include EventsHelper by default, as the first test has verified (I think)
#event = Event.new
# call method to check output
#event.filter_check_button_path.should be('/images/buttons/bt_search_for_events.gif')
end
end
When I've looked through the docs here - http://rspec.info/rails/writing/views.html, I'm mystified as to where the 'template' object comes from.
I've also tried looking here, which I thought would point me in the right direction, but alas, no dice. http://jakescruggs.blogspot.com/2007/03/mockingstubbing-partials-and-helper.html
What am I doing wrong here?
Thanks,
Chris
You are not doing anything in that spec, just setting a stub, so it will pass, but hasn't tested anything.
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe EventsHelper do
it "should return the 'refine image search' button if a search has been run" do
# mock up params hash
params = {:filter => true}
helper.stub!(:params).and_return(params)
helper.filter_check_button_path.should eql('/images/buttons/bt_search_for_events.gif')
end
end
I'm running my test without spec_helper (Ruby 1.9)
require_relative '../../app/helpers/users_helper'
describe 'UsersHelper' do
include UsersHelper
...
end
Ah,
I asked this question on the rspec mailing list, and one kind soul (thanks Scott!) explained to me that there's a handy helper object for this, that you should use instead, like so:
Rails has its own helper function
params = {:filter => true}
helper.stub!(:params).and_return(params)
I've now updated the code like so:
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe EventsHelper do
#Delete this example and add some real ones or delete this file
it "should be included in the object returned by #helper" do
included_modules = (class << helper; self; end).send :included_modules
included_modules.should include(EventsHelper)
end
it "should return the 'refine image search' button if a search has been run" do
# mock up params hash
params = {}
params[:filter] = true
helper.stub!(:filter_check_button_path).and_return('/images/buttons/bt_search_for_events.gif')
end
end
And it's working. Huzzah!