ERROR - Runtime.HandlerNotFound: Handler 'lambda_handler' missing on module 'lambda_function' - python-3.x

My apologies for basic question. I am completely new to AWS as well as Python. I am trying to do sample code but facing a error. I'm trying to read some data from a dynamodb table, but facing error like this in AWS Cloudwatch logs:
"Runtime.HandlerNotFound: Handler 'lambda_handler' missing on module 'lambda_function'".
And Postman is throwing error as
"message": "Internal server error"
The code is:
import boto3
class userProfile:
def __init__(self):
dynamodb = boto3.resource('dynamodb')
self.table = dynamodb.Table('user_data')
def Create_table():
pass
def Read_table(self, event):
response = self.table.get_item(
Key = {
'user_name' : event['user_name']
}
)
if 'Item' in response:
return response['Item']
else:
return {
'statusCode':'404',
'body' : 'User Name ' + 'id ' + 'not found'
}
def Update_tabel():
pass
def lambda_handler(event, context):
if event:
user_Object = userProfile()
if event["tasktype"] == "read":
read_result = user_Object.Read_table(event['data'])
return read_result
else:
return {
'statusCode': '404',
'body': 'Not found'
}

Related

Testing my Flask application with pytests gives status code 422 ('Missing data for required field.') even though data is passed

So I have this flask application and I'm trying to test it with pytest
app.py:
import os
from flask import Flask, jsonify
from flask_smorest import Api
from flask_jwt_extended import JWTManager
from flask_migrate import Migrate
from db import db
from resources.item import blp as ItemBlueprint
from resources.store import blp as StoreBlueprint
from resources.tag import blp as TagBlueprint
from resources.user import blp as UserBlueprint
from blocklist import BLOCKLIST
def create_app(db_url=None):
app = Flask(__name__)
app.config["PROPAGATE_EXCEPTIONS"] = True
app.config["API_TITLE"] = "Stores REST API"
app.config["API_VERSION"] = "v1"
app.config["OPENAPI_VERSION"] = "3.0.3"
app.config["OPENAPI_URL_PREFIX"] = "/"
app.config["OPENAPI_SWAGGER_UI_PATH"] = "/swagger-ui"
app.config["OPENAPI_SWAGGER_UI_URL"] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist/"
app.config["SQLALCHEMY_DATABASE_URI"] = db_url or os.getenv("DATABASE_URL", "sqlite:///data.db")
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
db.init_app(app)
api = Api(app)
migrate = Migrate(app, db)
app.config['JWT_SECRET_KEY'] = '69490938337699758397870296439802775085'
jwt = JWTManager(app)
#jwt.needs_fresh_token_loader
def token_not_fresh_callback(jwt_header, jwt_payload):
return (
jsonify(
{
"description": "The token is not fresh.",
"error": "fresh_token_required",
}
),
401,
)
#jwt.token_in_blocklist_loader
def check_if_token_in_blocklist(jwt_header, jwt_payload):
return jwt_payload['jti'] in BLOCKLIST
#jwt.revoked_token_loader
def revoked_token_callback(jwt_header, jwt_payload):
return (
jsonify(
{
"description": "The token has been revoked.",
"error": "token_revoked"
}
)
)
#jwt.additional_claims_loader
def add_claims_to_jwt(identity):
if identity == 1:
return {"is_admin": True}
return {"is_admin": False}
#jwt.expired_token_loader
def expired_token_callback(jwt_header, jwt_payload):
return (
jsonify(
{
"message": "The token has expired.",
"error": "token_expired"
}
),
401,
)
#jwt.invalid_token_loader
def invalid_token_callback(error):
return (
jsonify(
{
"message": "Signature verification failed.",
"error": "invalid_token"
}
), 401,
)
#jwt.unauthorized_loader
def missing_token_callback(error):
return (
jsonify(
{
"description": "Request does not contain an access token.",
"error": "authorization_required",
}
), 401,
)
# #app.before_first_request
# def create_tables():
# db.create_all()
api.register_blueprint(ItemBlueprint)
api.register_blueprint(StoreBlueprint)
api.register_blueprint(TagBlueprint)
api.register_blueprint(UserBlueprint)
return app
And I am trying to test some endpoints like create a store, so I'm doing this in the tests/conftest.py
from app import create_app
#pytest.fixture(scope='module')
def client():
flask_app = create_app()
flask_app.testing = True
flask_app.testing = True
with flask_app.test_client() as testing_client:
with flask_app.app_context():
yield testing_client
And there is the test for creation of a store
from flask_jwt_extended import create_access_token
def test_store_creation(client):
"""
GIVEN a Store model
WHEN a new Store is created
THEN check the name field is defined correctly
"""
access_token = create_access_token('admin')
headers = {
'Authorization': 'Bearer {}'.format(access_token)
}
response = client.post('/store', data={"name": "test_store"}, headers=headers)
print(response.get_json())
assert response.status_code == 201
The Store schema
class PlainItemSchema(Schema):
id = fields.Str(dump_only=True)
name = fields.Str(required=True)
price = fields.Float(required=True)
class PlainTagSchema(Schema):
id = fields.Int(dump_only=True)
name = fields.Str()
class PlainStoreSchema(Schema):
id = fields.Str(dump_only=True)
name = fields.Str(required=True)
class StoreSchema(PlainStoreSchema):
items = fields.List(fields.Nested(PlainItemSchema()), dump_only=True)
tags = fields.List(fields.Nested(PlainTagSchema()), dump_only=True)
My Store Blueprint
from flask.views import MethodView
from flask_smorest import abort, Blueprint
from sqlalchemy.exc import SQLAlchemyError, IntegrityError
from flask_jwt_extended import jwt_required, get_jwt
from schemas import StoreSchema
from db import db
from models import StoreModel
blp = Blueprint('stores', __name__, description='Operations on stores')
#blp.route('/store/<int:store_id>')
class Store(MethodView):
#blp.response(200, StoreSchema)
def get(self, store_id):
store = StoreModel.query.get_or_404(store_id)
return store
#jwt_required(fresh=True)
def delete(self, store_id):
"""Only admins can delete stores"""
jwt = get_jwt()
if not jwt.get('is_admin'):
abort(400, message='Admin privilege required.')
store = StoreModel.query.get_or_404(store_id)
db.session.delete(store)
db.session.commit()
return {"message": "Store deleted"}
#blp.route("/store")
class StoreList(MethodView):
#blp.response(200, StoreSchema(many=True))
def get(self):
return StoreModel.query.all()
#jwt_required()
#blp.arguments(StoreSchema)
#blp.response(201, StoreSchema)
def post(self, store_data):
store = StoreModel(**store_data)
try:
db.session.add(store)
db.session.commit()
except IntegrityError:
abort(
400,
message="A store with that name already exists.",
)
except SQLAlchemyError:
abort(500, message="An error occurred creating the store.")
return store
The error I'm getting is this
============================= test session starts ==============================
collecting ... collected 1 item
test_stores.py::test_store_creation FAILED [100%]{'code': 422, 'errors': {'json': {'name': ['Missing data for required field.']}}, 'status': 'Unprocessable Entity'}
test_stores.py:4 (test_store_creation)
422 != 201
Expected :201
Actual :422
<Click to see difference>
client = <FlaskClient <Flask 'app'>>
def test_store_creation(client):
"""
GIVEN a Store model
WHEN a new Store is created
THEN check the name field is defined correctly
"""
data = {
"name": "test"
}
access_token = create_access_token('admin')
headers = {
'Authorization': 'Bearer {}'.format(access_token)
}
response = client.post('/store', headers=headers, data=data)
print(response.get_json())
> assert response.status_code == 201
E assert 422 == 201
E + where 422 = <WrapperTestResponse 109 bytes [422 UNPROCESSABLE ENTITY]>.status_code
test_stores.py:22: AssertionError
It's like I'm not sending any data in the cliet.post() method, In fact if I remove the 'data={'name': 'test'}' I get the same result.
I tried to put data dict outside the method and convert it to json with json.dumps(data) still getting the result
flask-smorest is expecting you to post json data as default, so automatically send it as json OR adjust your header manually to reflect the data your are sending.
Fix your code as:
response = client.post("/store", json={"name": "test_store"}, headers=headers)

AWS API Gateway/Lambda/DynamoDB - .get_item() not finding item in table

I currently have POSTed items into the DynamoDB (the date is a string):
dynamodb
When I try accessing this via a GET, I get 404 not found (not a 502 so it appears the lambda response is OK):
get request
This is the code in my lambda function:
def lambda_handler(event, context):
logger.info(event)
httpMethod = event['httpMethod']
path = event['path']
if httpMethod == getMethod and path == answersPath:
response = buildResponse(200)
elif httpMethod == getMethod and path == dailyAnswerPath:
response = getAnswer(event['queryStringParameters']['day'])
else:
response = buildResponse(404, 'Not Found')
return response
def getAnswer(day):
try:
response = table.get_item(
Key = {
'day': day
}
)
if 'answer' in response:
return buildResponse(200, response['answer'])
else:
return buildResponse(404, {'Message':'Day %s not found' %day})
except:
logger.exception('getAnswer error day %s' %day)
def buildResponse(statusCode, body=None):
response = {
'statusCode': statusCode,
'headers': {
'Content-Type':'application/json',
'Access-Control-Allow-Origin': '*'
}
}
if body is not None:
response['body'] = json.dumps(body, cls=encodeddd)
return response

Using json.dump and json_enccode format to requests.post ,server return Response [500],serve use tornade.escape.json_decode

Using Python 3.8.10 and requests 2.21.0
The service post handle function below:
from tornado.escape import json_decode
def get_payload(self):
return json_decode(self.request.body)
def post(self):
""" acquire device """
data = self.get_payload()
udid = data["udid"]
idle_timeout = data.get('idleTimeout', 600)
email = self.current_user.email
try:
await D(udid).acquire(email, idle_timeout)
self.write_json({
"success": True,
"description": "Device successfully added"
})
except AcquireError as e:
self.set_status(403) # forbidden
self.write_json({
"success": False,
"description": "Device add failed: " + str(e),
})
The Client post fun below:
def post_occupied_device(self,udid = None,idleTimeout = None):
url = self.SERVER_URL+'/api/v1/user/devices'
occupied_dict = {
"udid": udid
}
try:
resp = requests.post(url,json=json.dumps(occupied_dict),headers=self.headers)
except requests.exceptions.RequestException as e:
print(e)
return "failed,network error"
print(resp)
enter code here
The server return:<Response [500]>
Then i change json data to this :
resp = requests.post(url,json=json_encode(occupied_dict),headers=self.headers)
The server return:<Response [500]>
Then i change json data to this :
requests.post(url,json=occupied_dict,headers=self.headers)
it is ok,The server return:<Response [200]>
i checkout the result and type between json_encode and json.dumps:
import json
from tornado.escape import json_encode
occupied_json = {
"udid": "DFEFDGDSGDF"
}
occupied_dict = {
'udid': "DFEFDGDSGDF"
}
req1 = json.dumps(occupied_json)
req2 = json_encode(occupied_json)
print(req1,type(req1))
print(req2,type(req2))
they are the same:
{"udid": "DFEFDGDSGDF"} <class 'str'>
{"udid": "DFEFDGDSGDF"} <class 'str'>
so,why?

How do i test except Errors using side_effect in python unittest mock?

I am a junior developer and trying to write some unittests for our API endpoints. Below is the class that i am testing and the actual test that runs without any issue. (But i am still hesitant that it's hitting my methods). My question is how can i improve my test and also make sure it covers exception(in this case ValueError, SystemError, Exception) by using side_effects(or any better suggestions) from python mock? I read python mock documentation but still can't figure out how to improve and importantly test exceptions.
we use flask microframework, python3.x,
--- Class that i am testing:
#USER_MOD.route('', methods=[HttpMethods.HTTP_POST])
#jwt_required
def create_user():
"""
Private end point for creating users of the system
:return: json
"""
response = ""
try:
logger_obj.info("Request : POST : Create User: {} ".format(request.base_url))
# validating input request
if ValidationUtils.validate_request(request, "CREATE_USER"):
logger_obj.debug("Request Validation Successful")
response = UserService().create_new_user(request)
logger_obj.debug("User Created: {} ".format(response))
return jsonify(response), HTTPStatus.OK
except ValueError as error:
logger_obj.error("ValueError create_user() : {}".format(error))
response = ApplicationUtils.create_api_response(status=ResponseConstants.MSG_ERROR, message=str(error))
return jsonify(response), HTTPStatus.BAD_REQUEST
except SystemError as error:
logger_obj.error("SystemError create_user() : {}".format(error))
response = ApplicationUtils.create_api_response(status=ResponseConstants.MSG_ERROR, message=str(error))
return jsonify(response), HTTPStatus.INTERNAL_SERVER_ERROR
except Exception as error:
logger_obj.error("Exception create_user() : {}".format(error))
response = ApplicationUtils.create_api_response(status=ResponseConstants.MSG_ERROR, message=str(error))
return jsonify(response), HTTPStatus.UNAUTHORIZED
finally:
logger_obj.info("Response : POST : Create User: {} : {}".format(request.base_url, response))
--- Test for above class:
class UserApiTests(DataTestCase): //(or i can use unittest.TestCase)
def setUp(self):
os.environ.update(self.config.to_env())
self.flask_app = make_flask_app()
self.client = self.flask_app.test_client()
self.flask_app.testing = True
#patch('usermgmt.app.services.user_service.UserService.create_new_user')
def test_create_user(self, mock_create_new_user):
# Given
mock_create_new_user.return_value.status_code = 200
mock_create_new_user.return_value = {
"status": "SUCCESS"
}
data_to_post = {
"name": "Test2",
"email": "new-user2#entity.com",
"entity_id": 1,
"is_active": True,
"product_roles": [
{"product_id": 1, "role_id": 4},
{"product_id": 2, "role_id": 4}
],
}
# When
response = self.client.post('/api/usermgmt/users', data=json.dumps(data_to_post), headers={
"Authorization": "Bearer {}".format(get_jwt(identity=self), "Content-Type: application/json")
})
data = response.data
json_data = json.loads(data)
# Then
self.assertEqual(response.status_code, 200)
self.assertEqual(json_data['status'], "SUCCESS")
During my practice I've found that approach quite good.
class TestCreateUser(TestCase):
def test_works_in_correct_case(self):
# equal to your test_create_user
#patch("usermgmt.app.services.user_service.UserService.create_new_user")
def test_handles_value_error_in_create_new_user(self, mock_create_new_user):
mock_create_new_user.side_effect = ValueError
# Your preparation flow here
response = self.client.post('/api/usermgmt/users') # simplified call here is just an example
self.assertEqual(response.status_code, 400)
# check if response body is what you've expected, etc.

Mock exception raised in function using Pytest

I have the following function and it is a generic function which will make API call based on the input hostname and data. It will construct http request to make API and will return the response. This function will throw four types of exception(invalid URL, timeout, auth error and status check). How can I Mcok and Test the exception raised in API call using pytest? Which will be the best method to test the exceptions raised from API call?
import ssl
import urllib
import urllib.request
import urllib.error
import xml
import xml.etree.ElementTree as ET
def call_api(hostname, data):
'''Function to make API call
'''
# Todo:
# Context to separate function?
# check response for status codes and return reponse.read() if success
# Else throw exception and catch it in calling function
error_codes = {
"1": "Unknown command",
"6": "Bad Xpath",
"7": "Object not present",
"8": "Object not unique"
}
url = "http://" + hostname + "/api"
encoded_data = urllib.parse.urlencode(data).encode('utf-8')
try:
response = urllib.request.urlopen(url, data=encoded_data,
timeout=10).read()
root = ET.fromstring(response)
if root.attrib.get('status') != "success":
Errorcode = root.attrib.get('code')
raise Exception(pan_error_codes.get(Errorcode, "UnknownError"),
response)
else:
return response
except urllib.error.HTTPError as e:
raise Exception(f"HttpError: {e.code} {e.reason} at {e.url}", None)
except urllib.error.URLError as e:
raise Exception(f"Urlerror: {e.reason}", None)
If i call this function
def create_key(hostname, username, password):
hostname = 'myhost ip'
data = {
'type': 'keygen',
'username': username,
'password': password
}
username = 'myuser'
password = 'password'
response = call_api(hostname, data)
return response
i will get a response like following
b"<response status = 'success'><result><key>mykey</key></result></response>"
You can mock error raising via side_effect parameter:
Alternatively side_effect can be an exception class or instance. In this case the exception will be raised when the mock is called.
In your case, this can be used like this (assuming call_api is defined in module foo):
import pytest
from unittest.mock import patch
def test_api():
with patch('foo.call_api', side_effect=Exception('mocked error')):
with pytest.raises(Exception) as excinfo:
create_key('localhost:8080', 'spam', 'eggs')
assert excinfo.value.message == 'mocked error'

Resources