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
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_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
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

    # 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)
Beispiel #7
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 = [{
            'Key': {
                'MockHash': {
                    'N': '2'
                },
                'MockRange': {
                    'N': '4'
                }
            },
            'TableName': 'mock'
        }]
        expected_puts = [{
            'Item': {
                'MockHash': {
                    'N': '3'
                },
                'MockRange': {
                    'N': '5'
                }
            },
            'TableName': 'mock'
        }]
        expected_updates = [{
            'TableName': 'mock',
            'Key': {
                'MockHash': {
                    'N': '4'
                },
                'MockRange': {
                    'N': '6'
                }
            },
            'ReturnValuesOnConditionCheckFailure': 'ALL_OLD',
            'UpdateExpression': 'SET #0 = :0',
            'ExpressionAttributeNames': {
                '#0': 'mock_toot'
            },
            'ExpressionAttributeValues': {
                ':0': {
                    'S': 'hello'
                }
            }
        }]

        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)
Beispiel #8
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)