def test_is_occ_conflict_exception_false(self, mock_client_error):
     mock_client_error.response = {
         'Error': {
             'Code': 'NotOccConflictException'
         }
     }
     self.assertFalse(is_occ_conflict_exception(mock_client_error))
def commit_transaction(qldb_session, transaction, statement, parameters):
    """
    Commit the transaction and retry up to a constant number of times.

    :type qldb_session: :py:class:`pyqldb.session.qldb_session.QldbSession`
    :param qldb_session: An instance of the QldbSession class.

    :type transaction: :py:class:`pyqldb.transaction.transaction.Transaction`
    :param transaction: An instance of the Transaction class.

    :type statement: str
    :param statement: The query to execute.

    :type parameters: list
    :param parameters: list of parameters in Ion format.
    """
    for i in range(Constants.RETRY_LIMIT):
        try:
            transaction.commit()
            logger.info('Commit successful after {} retries.'.format(i))
            break
        except ClientError as ce:
            if is_occ_conflict_exception(ce):
                logger.error('Commit failed due to an OCC conflict. Restart transaction.')
                transaction = qldb_session.start_transaction()
                execute_transaction(qldb_session, transaction, statement, parameters)
def execute_transaction(qldb_session, transaction, statement, parameters):
    """
    Execute statement with parameters. If it was unsuccessful, retry with a new transaction.

    :type qldb_session: :py:class:`pyqldb.session.qldb_session.QldbSession`
    :param qldb_session: An instance of the QldbSession class.

    :type transaction: :py:class:`pyqldb.transaction.transaction.Transaction`
    :param transaction: An open transaction.

    :type statement: str
    :param statement: The query to execute.

    :type parameters: list
    :param parameters: list of parameters in Ion format.
    """
    for i in range(Constants.RETRY_LIMIT):
        try:
            transaction.execute_statement(statement, parameters)
            logger.info('Execute successful after {} retries.'.format(i))
            break
        except ClientError as ce:
            if is_occ_conflict_exception(ce):
                logger.error('Execute on QLDB session failed due to an OCC conflict. Restart transaction.')
                transaction = qldb_session.start_transaction()
    def test_occ_exception_is_thrown(self):
        # Create driver with zero retry limit to trigger OCC exception.
        driver = self.integration_test_base.qldb_driver(retry_limit=0)

        # Insert document.
        ion_value = loads(dumps({COLUMN_NAME: 0}))

        def execute_statement_with_parameter_and_return_count(
                txn, query, parameter):
            cursor = txn.execute_statement(query, parameter)
            count = 0
            for row in cursor:
                count += 1
            return count

        query = "INSERT INTO {} ?".format(TABLE_NAME)
        count = driver.execute_lambda(
            lambda txn: execute_statement_with_parameter_and_return_count(
                txn, query, ion_value))
        self.assertEqual(1, count)

        # For testing purposes only. Forcefully causes an OCC conflict to occur.
        # Do not invoke driver.execute_lambda within the parameter function under normal circumstances.
        def query_and_update_record(transaction_executor):
            # Query document.
            transaction_executor.execute_statement(
                "SELECT VALUE {} FROM {}".format(COLUMN_NAME, TABLE_NAME))
            # The following update document will be committed before query document thus resulting in OCC.
            driver.execute_lambda(
                lambda transaction_executor: transaction_executor.
                execute_statement(
                    "UPDATE {} SET {} = ?".format(TABLE_NAME, COLUMN_NAME), 5))

        try:
            driver.execute_lambda(lambda txn: query_and_update_record(txn))
            self.fail("Did not throw OCC exception.")
        except ClientError as ce:
            self.assertTrue(is_occ_conflict_exception(ce))
 def test_is_occ_conflict_exception_not_client_error(self):
     self.assertFalse(is_occ_conflict_exception(Exception()))
 def test_is_occ_conflict_exception_false(self):
     clientError = ClientError(
         {'Error': {
             'Code': 'NotOccConflictException'
         }}, 'SendCommand')
     self.assertFalse(is_occ_conflict_exception(clientError))