Moto对AWS DynamoDB的模拟调用返回模糊区域KeyError

时间:2019-11-16 23:50:44

标签: python-3.x amazon-dynamodb boto3 moto

我正在尝试测试Lambda函数处理程序,该函数处理程序调用DynamoDb并在部署时可以工作,但是在测试Moto时似乎在设置阶段遇到了麻烦,并产生了模糊的错误。测试代码如下:

# -*- coding: utf-8 -*-
from model.terrestrial import Terrestrial

import pytest
import moto
import boto3
import os
import json

REGION = 'ap-southwest-2'
TERRESTRIAL_TABLE_NAME = 'U_terrestrial'
os.environ['TERRESTRIAL_TABLE_NAME'] = TERRESTRIAL_TABLE_NAME
os.environ['PRIMARY_KEY'] = 'id'

from lambdas import terrestrial_persist_function as func
from tests.lambdas import api_gateway_event

@pytest.fixture
def dynamodb_table():
    with moto.mock_dynamodb2():
        boto3.client('dynamodb', region_name=REGION).create_table(
            AttributeDefinitions=[
                {'AttributeName': 'id', 'AttributeType': 'S'}
            ],
            TableName=TERRESTRIAL_TABLE_NAME,
            KeySchema=[{'AttributeName': 'id', 'KeyType': 'HASH'}],
            ProvisionedThroughput={
                'ReadCapacityUnits': 1,
                'WriteCapacityUnits': 1,
            },
        )
        yield boto3.resource('dynamodb', region_name=REGION).Table(TERRESTRIAL_TABLE_NAME)


@pytest.fixture
def mercury():
    file = open('../fixtures/db_2_terrestrial_mercury.json', 'r')
    obj: Terrestrial = Terrestrial.dict_to_object(json.loads(file.read().strip()))
    file.close()
    return obj.dict_dynamodb()


@pytest.fixture
def venus():
    file = open('../fixtures/db_3_terrestrial_venus.json', 'r')
    obj: Terrestrial = Terrestrial.dict_to_object(json.loads(file.read().strip()))
    file.close()
    return obj.dict_dynamodb()


@pytest.fixture
def earth():
    file = open('../fixtures/db_4_0_terrestrial_earth.json', 'r')
    obj: Terrestrial = Terrestrial.dict_to_object(json.loads(file.read().strip()))
    file.close()
    return obj.dict_dynamodb()


@pytest.fixture
def luna():
    file = open('../fixtures/db_4_0_terrestrial_luna.json', 'r')
    obj: Terrestrial = Terrestrial.dict_to_object(json.loads(file.read().strip()))
    file.close()
    return obj.dict_dynamodb()


@pytest.fixture
def mars():
    file = open('../fixtures/db_5_0_terrestrial_mars.json', 'r')
    obj: Terrestrial = Terrestrial.dict_to_object(json.loads(file.read().strip()))
    file.close()
    return obj.dict_dynamodb()


@pytest.fixture
def all_terrestrials(mercury, venus, earth, luna, mars) -> []:

    return [mercury, venus, earth, luna, mars]


def headers():
    return {
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Credentials": "True",
        "Content-Type": "application/json"
    }


def test_get_terrestrials_ok(dynamodb_table, all_terrestrials):
    # given
    print('table: {}'.format(TERRESTRIAL_TABLE_NAME))
    print('os table: {}'.format(os.environ['TERRESTRIAL_TABLE_NAME']))

    dirpath = os.getcwd()
    print("current directory is : " + dirpath)

    with dynamodb_table.batch_writer() as batch:
        for i in all_terrestrials:
            batch.put_item(Item=i)

    # when
    resp = func.handler(
        api_gateway_event(
            '/terrestrial',
            'GET',
            {}
        ), None)

    # then
    assert resp['statusCode'] == 200
    assert resp['headers'] == headers()
    assert resp['body'] == json.dumps(all_terrestrials())


def test_get_terrestrials_empty(dynamodb_table):
    print('table: {}'.format(TERRESTRIAL_TABLE_NAME))

    print('os table: {}'.format(os.environ['TERRESTRIAL_TABLE_NAME']))

    dirpath = os.getcwd()
    print("current directory is : " + dirpath)

    # when
    resp = func.handler(
            api_gateway_event(
                '/terrestrial',
                'GET',
                {}
            ), None)

    # then
    assert resp['statusCode'] == 200
    assert resp['headers'] == headers()
    assert resp['body'] == '[]'


def test_get_terrestrial_ok(dynamodb_table, all_terrestrials):
    print('table: {}'.format(TERRESTRIAL_TABLE_NAME))

    print('os table: {}'.format(os.environ['TERRESTRIAL_TABLE_NAME']))

    dirpath = os.getcwd()
    print("current directory is : " + dirpath)

    with dynamodb_table.batch_writer() as batch:
        for i in all_terrestrials:
            batch.put_item(Item=i)

    # when
    resp = func.handler(
            api_gateway_event(
                '/terrestrial/40743816-c884-4c79-9ab4-6dd4c740c52c',
                'GET',
                {}
            ), None)

    # then
    assert resp['statusCode'] == 200
    assert resp['headers'] == headers()
    assert resp['body'] == json.dumps(earth())


def test_get_terrestrial_not_found(dynamodb_table):
    print('table: {}'.format(TERRESTRIAL_TABLE_NAME))

    print('os table: {}'.format(os.environ['TERRESTRIAL_TABLE_NAME']))

    dirpath = os.getcwd()
    print("current directory is : " + dirpath)

    # when
    resp = func.handler(
            api_gateway_event(
                '/terrestrial/00000000-0000-0000-0000-000000000000',
                'GET',
                {}
            ), None)

    # then
    assert resp['statusCode'] == 200
    assert resp['headers'] == headers()
    assert resp['body'] == {}

(针对每个测试)产生的错误是:

ERROR [ 25%]
test setup failed
@pytest.fixture
    def dynamodb_table():
        with moto.mock_dynamodb2():
            boto3.client('dynamodb', region_name=REGION).create_table(
                AttributeDefinitions=[
                    {'AttributeName': 'id', 'AttributeType': 'S'}
                ],
                TableName=TERRESTRIAL_TABLE_NAME,
                KeySchema=[{'AttributeName': 'id', 'KeyType': 'HASH'}],
                ProvisionedThroughput={
                    'ReadCapacityUnits': 1,
>                   'WriteCapacityUnits': 1,
                },
            )

../lambdas/test_terrestrial_persist_function.py:37: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/client.py:320: in _api_call
    return self._make_api_call(operation_name, kwargs)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/client.py:611: in _make_api_call
    operation_model, request_dict)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/endpoint.py:102: in make_request
    return self._send_request(request_dict, operation_model)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/endpoint.py:136: in _send_request
    success_response, exception):
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/endpoint.py:210: in _needs_retry
    caught_exception=caught_exception, request_dict=request_dict)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/hooks.py:356: in emit
    return self._emitter.emit(aliased_event_name, **kwargs)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/hooks.py:228: in emit
    return self._emit(event_name, kwargs)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/hooks.py:211: in _emit
    response = handler(**kwargs)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/retryhandler.py:183: in __call__
    if self._checker(attempts, response, caught_exception):
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/retryhandler.py:251: in __call__
    caught_exception)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/retryhandler.py:269: in _should_retry
    return self._checker(attempt_number, response, caught_exception)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/retryhandler.py:317: in __call__
    caught_exception)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/retryhandler.py:223: in __call__
    attempt_number, caught_exception)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/retryhandler.py:359: in _check_caught_exception
    raise caught_exception
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/endpoint.py:176: in _get_response
    responses = self._event_emitter.emit(event_name, request=request)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/hooks.py:356: in emit
    return self._emitter.emit(aliased_event_name, **kwargs)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/hooks.py:228: in emit
    return self._emit(event_name, kwargs)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/botocore/hooks.py:211: in _emit
    response = handler(**kwargs)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/moto/core/models.py:292: in __call__
    status, headers, body = response_callback(request, request.url, request.headers)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/moto/core/responses.py:117: in dispatch
    return cls()._dispatch(*args, **kwargs)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/moto/core/responses.py:200: in _dispatch
    return self.call_action()
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/moto/core/utils.py:264: in _wrapper
    response = f(*args, **kwargs)
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/moto/dynamodb2/responses.py:64: in call_action
    response = getattr(self, endpoint)()
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/moto/dynamodb2/responses.py:108: in create_table
    table = self.dynamodb_backend.create_table(table_name,
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <moto.dynamodb2.responses.DynamoHandler object at 0x122590f50>

    @property
    def dynamodb_backend(self):
        """
        :return: DynamoDB2 Backend
        :rtype: moto.dynamodb2.models.DynamoDBBackend
        """
>       return dynamodb_backends[self.region]
E       KeyError: 'ap-southwest-2'

/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/moto/dynamodb2/responses.py:56: KeyError

为了减少这个问题的冗长性,我省略了我正在测试的lambda,因为我不相信我们会走得那么远。看来Moto没有正确设置。但是,如果您需要它,我可以在以后的编辑中提供它。

如您所见,错误非常模糊(我希望我的问题不是这样),而且我不确定如何从哪里开始对这个问题进行故障排除。任何帮助将不胜感激。

从requirements.txt:

pytest==5.1.1
boto3==1.9.66
botocore==1.12.67
moto==1.3.7

0 个答案:

没有答案