Mocking a lambda response with moto

11.2k views Asked by At

Somewhere in my code, a lambda is called to return a true/false response. I am trying to mock this lambda in my unit tests with no success.

This is my code:

def _test_update_allowed():
    old = ...
    new = ...
    assert(is_update_allowed(old, new) == True)

Internally, is_update_allowed calls the lambda, which is what I want to mock.

I tried adding the following code above my test:

import zipfile
import io
import boto3
import os

@pytest.fixture(scope='function')
def aws_credentials():
    """Mocked AWS Credentials for moto."""
    os.environ['AWS_ACCESS_KEY_ID'] = 'testing'
    os.environ['AWS_SECRET_ACCESS_KEY'] = 'testing'
    os.environ['AWS_SECURITY_TOKEN'] = 'testing'
    os.environ['AWS_SESSION_TOKEN'] = 'testing'


CLIENT = boto3.client('lambda', region_name='us-east-1')

# Expected response setup and zip file for lambda mock creation
def lambda_event():
    code = '''
        def lambda_handler(event, context):
            return event
        '''
    zip_output = io.BytesIO()
    zip_file = zipfile.ZipFile(zip_output, 'w', zipfile.ZIP_DEFLATED)
    zip_file.writestr('lambda_function.py', code)
    zip_file.close()
    zip_output.seek(0)
    return zip_output.read()

# create mocked lambda with zip file
def mock_some_lambda(lambda_name, return_event):
    return CLIENT.create_function(
        FunctionName=lambda_name,
        Runtime='python2.7',
        Role='arn:aws:iam::123456789:role/does-not-exist',
        Handler='lambda_function.lambda_handler',
        Code={
            'ZipFile': return_event,
        },
        Publish=True,
        Timeout=30,
        MemorySize=128
    )

and then updated my test to:

@mock_lambda
def _test_update_allowed():
    mock_some_lambda('hello-world-lambda', lambda_event())
    old = ...
    new = ...
    assert(is_update_allowed(old, new) == True)

But I'm getting the following error, which makes me think it's actually trying to talk to AWS

botocore.exceptions.ClientError: An error occurred (UnrecognizedClientException) when calling the CreateFunction operation: The security token included in the request is invalid.
2

There are 2 answers

2
samtoddler On

From the error message, I can confirm it definitely not an AWS issue. It is clearly stating that it is trying to use some credentials which are not valid. So that boils down to the code.

I am assuming you already have import statements for necessary libs because those are also not visible in the shared code

import pytest
import moto

from mock import mock, patch
from moto import mock_lambda

So you need to use the

def aws_credentials():
 .....

while creating the client because from the code I dont see that you are using the same.

@pytest.fixture(scope='function')
def lambda_mock(aws_credentials):
with mock_lambda():
    yield boto3.client('lambda', region_name='us-east-1')

and eventually your mock

@pytest.fixture(scope='function')
def mock_some_lambda(lambda_mock):
    lambda_mock.create_function(
        FunctionName=lambda_name,
        Runtime='python2.7',
        Role='arn:aws:iam::123456789:role/does-not-exist',
        Handler='lambda_function.lambda_handler',
        Code={
            'ZipFile': return_event,
        },
        Publish=True,
        Timeout=30,
        MemorySize=128
    )
 yield

then test function

    def _test_update_allowed(lambda_mock,mock_some_lambda):
        lambda_mock.invoke(...)
          .....

Cant give a working example, because not sure what the full logic is. Between take a look this post.

0
Nikita On

The problems seems due to unexisting arn role. Try mocking it like in moto library tests

def get_role_name():
    with mock_iam():
        iam = boto3.client("iam", region_name=_lambda_region)
        try:
            return iam.get_role(RoleName="my-role")["Role"]["Arn"]
        except ClientError:
            return iam.create_role(
                RoleName="my-role",
                AssumeRolePolicyDocument="some policy",
                Path="/my-path/",
            )["Role"]["Arn"]