Пример #1
0
def test_transaction_write_with_version_attribute_condition_failure(
        connection):
    foo = Foo(21)
    foo.save()

    foo2 = Foo(21)

    with pytest.raises(TransactWriteError) as exc_info:
        with TransactWrite(connection=connection) as transaction:
            transaction.save(Foo(21))
    assert get_error_code(exc_info.value) == TRANSACTION_CANCELLED
    assert 'ConditionalCheckFailed' in get_error_message(exc_info.value)

    with pytest.raises(TransactWriteError) as exc_info:
        with TransactWrite(connection=connection) as transaction:
            transaction.update(foo2, actions=[
                Foo.star.set('birdistheword'),
            ])
    assert get_error_code(exc_info.value) == TRANSACTION_CANCELLED
    assert 'ConditionalCheckFailed' in get_error_message(exc_info.value)
    # Version attribute is not updated on failure.
    assert foo2.version is None

    with pytest.raises(TransactWriteError) as exc_info:
        with TransactWrite(connection=connection) as transaction:
            transaction.delete(foo2)
    assert get_error_code(exc_info.value) == TRANSACTION_CANCELLED
    assert 'ConditionalCheckFailed' in get_error_message(exc_info.value)
Пример #2
0
def test_transact_write(connection):
    # making sure these entries exist, and with the expected info
    BankStatement(1, balance=0).save()
    BankStatement(2, balance=100).save()

    # assert values are what we think they should be
    statement1 = BankStatement.get(1)
    statement2 = BankStatement.get(2)
    assert statement1.balance == 0
    assert statement2.balance == 100

    with TransactWrite(connection=connection) as transaction:
        # let the users send money to one another
        # create a credit line item to user 1's account
        transaction.save(
            LineItem(user_id=1, amount=50, currency='USD'),
            condition=(LineItem.user_id.does_not_exist()),
        )
        # create a debit to user 2's account
        transaction.save(
            LineItem(user_id=2, amount=-50, currency='USD'),
            condition=(LineItem.user_id.does_not_exist()),
        )

        # add credit to user 1's account
        transaction.update(statement1, actions=[BankStatement.balance.add(50)])
        # debit from user 2's account if they have enough in the bank
        transaction.update(statement2,
                           actions=[BankStatement.balance.add(-50)],
                           condition=(BankStatement.balance >= 50))

    statement1.refresh()
    statement2.refresh()
    assert statement1.balance == statement2.balance == 50
Пример #3
0
def test_transact_write__one_of_each(connection):
    User(1).save()
    User(2).save()
    statement = BankStatement(1, balance=100, active=True)
    statement.save()

    with TransactWrite(connection=connection) as transaction:
        transaction.condition_check(User, 1, condition=(User.user_id.exists()))
        transaction.delete(User(2))
        transaction.save(LineItem(4, amount=100, currency='USD'),
                         condition=(LineItem.user_id.does_not_exist()))
        transaction.update(statement,
                           actions=[
                               BankStatement.active.set(False),
                               BankStatement.balance.set(0),
                           ])

    # confirming transaction correct and successful
    assert User.get(1)
    with pytest.raises(DoesNotExist):
        User.get(2)

    new_line_item = next(LineItem.query(4, scan_index_forward=False, limit=1),
                         None)
    assert new_line_item
    assert new_line_item.amount == 100
    assert new_line_item.currency == 'USD'

    statement.refresh()
    assert not statement.active
    assert statement.balance == 0
def test_transaction_write_with_version_attribute(connection):
    foo1 = Foo(1)
    foo1.save()
    foo2 = Foo(2, star='bar')
    foo2.save()
    foo3 = Foo(3)
    foo3.save()

    with TransactWrite(connection=connection) as transaction:
        transaction.condition_check(Foo, 1, condition=(Foo.bar.exists()))
        transaction.delete(foo2)
        transaction.save(Foo(4))
        transaction.update(
            foo3,
            actions=[
                Foo.star.set('birdistheword'),
            ]
        )

    assert Foo.get(1).version == 1
    with pytest.raises(DoesNotExist):
        Foo.get(2)
    # Local object's version attribute is updated automatically.
    assert foo3.version == 2
    assert Foo.get(4).version == 1
Пример #5
0
def test_transact_write__error__different_regions(connection):
    with pytest.raises(TransactWriteError) as exc_info:
        with TransactWrite(connection=connection) as transact_write:
            # creating a model in a table outside the region everyone else operates in
            transact_write.save(DifferentRegion(entry_index=0))
            transact_write.save(BankStatement(1))
            transact_write.save(User(1))
    assert get_error_code(exc_info.value) == RESOURCE_NOT_FOUND
def test_transact_write__error__multiple_operations_on_same_record(connection):
    BankStatement(1).save()

    # attempt to do a transaction with multiple operations on the same record
    with pytest.raises(TransactWriteError) as exc_info:
        with TransactWrite(connection=connection) as transaction:
            transaction.condition_check(BankStatement, 1, condition=(BankStatement.user_id.exists()))
            transaction.update(BankStatement(1), actions=[(BankStatement.balance.add(10))])
    assert get_error_code(exc_info.value) == VALIDATION_EXCEPTION
    assert BankStatement.Meta.table_name in exc_info.value.cause.MSG_TEMPLATE
def test_transact_write__error__idempotent_parameter_mismatch(connection):
    client_token = str(uuid.uuid4())

    with TransactWrite(connection=connection, client_request_token=client_token) as transaction:
        transaction.save(User(1))
        transaction.save(User(2))

    with pytest.raises(TransactWriteError) as exc_info:
        # committing the first time, then adding more info and committing again
        with TransactWrite(connection=connection, client_request_token=client_token) as transaction:
            transaction.save(User(3))
    assert get_error_code(exc_info.value) == IDEMPOTENT_PARAMETER_MISMATCH
    assert User.Meta.table_name in exc_info.value.cause.MSG_TEMPLATE

    # ensure that the first request succeeded in creating new users
    assert User.get(1)
    assert User.get(2)

    with pytest.raises(DoesNotExist):
        # ensure it did not create the user from second request
        User.get(3)
def test_transact_write__error__transaction_cancelled__condition_check_failure(connection):
    # create a users and a bank statements for them
    User(1).save()
    BankStatement(1).save()

    # attempt to do this as a transaction with the condition that they don't already exist
    with pytest.raises(TransactWriteError) as exc_info:
        with TransactWrite(connection=connection) as transaction:
            transaction.save(User(1), condition=(User.user_id.does_not_exist()))
            transaction.save(BankStatement(1), condition=(BankStatement.user_id.does_not_exist()))
    assert get_error_code(exc_info.value) == TRANSACTION_CANCELLED
    assert 'ConditionalCheckFailed' in get_error_message(exc_info.value)
    assert User.Meta.table_name in exc_info.value.cause.MSG_TEMPLATE
    assert BankStatement.Meta.table_name in exc_info.value.cause.MSG_TEMPLATE
Пример #9
0
 def _handle_transact_write(connection, auto_version_condition):
     old_auto_version_condition = MockModel.Meta.auto_version_condition
     MockModel.Meta.auto_version_condition = auto_version_condition
     with patch(PATCH_METHOD) as req:
         req.return_value = MOCK_TABLE_DESCRIPTOR
         with TransactWrite(connection=connection) as t:
             t.condition_check(
                 MockModel,
                 1,
                 3,
                 condition=(MockModel.mock_hash.does_not_exist()))
             t.delete(MockModel(2, 4))
             t.save(MockModel(3, 5))
             t.update(MockModel(4, 6),
                      actions=[MockModel.mock_toot.set('hello')],
                      return_values='ALL_OLD')
     MockModel.Meta.auto_version_condition = old_auto_version_condition
Пример #10
0
def handler(event, context):
    # Validation
    request = Request(**loads(event.get("body", {})))

    # Business logic, running safely under a transaction
    with TransactWrite(connection=Connection(),
                       client_request_token=generate_uuid()) as transaction:
        transaction.save(
            Store(
                name=request.name,
                delay=request.delay,
                working_since=request.working_since.strftime(
                    "%Y-%m-%d %H:%M:%S"),
            ))

        for employee_name in request.employees:
            transaction.save(Employee(name=employee_name))
Пример #11
0
 def test_condition_check__no_condition(self):
     with pytest.raises(TypeError):
         with TransactWrite(connection=Connection()) as transaction:
             transaction.condition_check(MockModel,
                                         hash_key=1,
                                         condition=None)
Пример #12
0
    office_out_of_date.save()

# After refreshing the local copy the operation will succeed.
office_out_of_date.refresh()
office_out_of_date.employees.remove(garrett)
office_out_of_date.save()
assert office_out_of_date.version == 3

# Condition check fails for delete.
with assert_condition_check_fails():
    office.delete()

# Example failed transactions.
connection = Connection(host='http://localhost:8000')

with assert_condition_check_fails(), TransactWrite(connection=connection) as transaction:
    transaction.save(Office(office.office_id, name='newer name', employees=[]))

with assert_condition_check_fails(), TransactWrite(connection=connection) as transaction:
    transaction.update(
        Office(office.office_id, name='newer name', employees=[]),
        actions=[
            Office.name.set('Newer Office Name'),
        ]
    )

with assert_condition_check_fails(), TransactWrite(connection=connection) as transaction:
    transaction.delete(Office(office.office_id, name='newer name', employees=[]))

# Example successful transaction.
office2 = Office(office_id=str(uuid4()), name="second office", employees=[justin])
Пример #13
0
    def test_commit(self, mocker):
        connection = Connection()
        mock_connection_transact_write = mocker.patch.object(
            connection, 'transact_write_items')
        with patch(PATCH_METHOD) as req:
            req.return_value = MOCK_TABLE_DESCRIPTOR
            with TransactWrite(connection=connection) as t:
                t.condition_check(
                    MockModel,
                    1,
                    3,
                    condition=(MockModel.mock_hash.does_not_exist()))
                t.delete(MockModel(2, 4))
                t.save(MockModel(3, 5))
                t.update(MockModel(4, 6),
                         actions=[MockModel.mock_toot.set('hello')],
                         return_values='ALL_OLD')

        expected_condition_checks = [{
            'ConditionExpression': 'attribute_not_exists (#0)',
            'ExpressionAttributeNames': {
                '#0': 'mock_hash'
            },
            'Key': {
                'MockHash': {
                    'N': '1'
                },
                'MockRange': {
                    'N': '3'
                }
            },
            'TableName': 'mock'
        }]
        expected_deletes = [{
            'ConditionExpression': 'attribute_not_exists (#0)',
            'ExpressionAttributeNames': {
                '#0': 'mock_version'
            },
            'Key': {
                'MockHash': {
                    'N': '2'
                },
                'MockRange': {
                    'N': '4'
                }
            },
            'TableName': 'mock'
        }]
        expected_puts = [{
            'ConditionExpression': 'attribute_not_exists (#0)',
            'ExpressionAttributeNames': {
                '#0': 'mock_version'
            },
            'Item': {
                'MockHash': {
                    'N': '3'
                },
                'MockRange': {
                    'N': '5'
                },
                'mock_version': {
                    'N': '1'
                }
            },
            'TableName': 'mock'
        }]
        expected_updates = [{
            'ConditionExpression': 'attribute_not_exists (#0)',
            'TableName': 'mock',
            'Key': {
                'MockHash': {
                    'N': '4'
                },
                'MockRange': {
                    'N': '6'
                }
            },
            'ReturnValuesOnConditionCheckFailure': 'ALL_OLD',
            'UpdateExpression': 'SET #1 = :0, #0 = :1',
            'ExpressionAttributeNames': {
                '#0': 'mock_version',
                '#1': 'mock_toot'
            },
            'ExpressionAttributeValues': {
                ':0': {
                    'S': 'hello'
                },
                ':1': {
                    'N': '1'
                }
            }
        }]
        mock_connection_transact_write.assert_called_once_with(
            condition_check_items=expected_condition_checks,
            delete_items=expected_deletes,
            put_items=expected_puts,
            update_items=expected_updates,
            client_request_token=None,
            return_consumed_capacity=None,
            return_item_collection_metrics=None)