Example #1
0
def test_wait_until_true_with_timeout(mock_time_sleep):
    """wait_until_true with dynamic invocation, exhaust wait attempts."""
    mock = MagicMock()
    mock.side_effect = [
        'test string 1',
        'test string 2',
        'test string 3',
        'test string 4',
        'test string 5',
        'test string 6',
        'test string 7',
        'test string 8',
        'test string 9',
        'test string 10',
        'test string 11',
    ]

    def decorate_me(arg1, arg2):
        """Test static decorator syntax"""
        assert arg1 == 'v1'
        assert arg2 == 'v2'
        if mock(arg1) == 'expected value':
            return True
        else:
            return False

    assert not poll.wait_until_true(interval=0.01,
                                    max_attempts=10)(decorate_me)('v1', 'v2')
    assert mock.call_count == 10
    mock.assert_called_with('v1')
    assert mock_time_sleep.call_count == 9
    mock_time_sleep.assert_called_with(0.01)
Example #2
0
def test_wait_until_true_once_not_found(mock_time_sleep):
    """wait_until_true max_attempts 1."""
    mock = MagicMock()
    mock.side_effect = [
        'test string 1',
        'test string 2',
    ]

    def decorate_me(arg1, arg2):
        """Test static decorator syntax."""
        assert arg1 == 'v1'
        assert arg2 == 'v2'
        return mock(arg1) == 'expected value'

    assert not poll.wait_until_true(interval=0.01, max_attempts=1)(
        decorate_me)('v1', 'v2')
    mock.assert_called_once_with('v1')
    mock_time_sleep.assert_not_called()
Example #3
0
def test_wait_until_true_invoke_inline(mock_time_sleep):
    """wait_until_true with dynamic invocation."""
    mock = MagicMock()
    mock.side_effect = [
        'test string 1', 'test string 2', 'test string 3', 'expected value',
        'test string 5'
    ]

    def decorate_me(arg1, arg2):
        """Test static decorator syntax"""
        assert arg1 == 'v1'
        assert arg2 == 'v2'
        if mock(arg1) == 'expected value':
            return True
        else:
            return False

    assert poll.wait_until_true(interval=0.01,
                                max_attempts=10)(decorate_me)('v1', 'v2')
    assert mock.call_count == 4
    mock.assert_called_with('v1')
    assert mock_time_sleep.call_count == 3
    mock_time_sleep.assert_called_with(0.01)
Example #4
0
def run_step(context):
    """Custom waiter for any aws client operation.

    All of the awsWaitFor descendant values support {key}
    string interpolation, except waitForField.

    Args:
        context:
            Dictionary. Mandatory.
            Requires the following context keys in context:
                - awsWaitFor. dict. mandatory. Contains keys:
                    - awsClientIn. dict. mandatory. This is the same as for the
                      pypyraws.steps.client in step. Contains keys:
                      - serviceName: mandatory. String for service name.
                                       Available services here:
                        http://boto3.readthedocs.io/en/latest/reference/services/
                      - methodName: mandatory. String. Name of method to
                                    execute.
                      - clientArgs: optional. Dict. kwargs for the boto client
                                    ctor.
                      - methodArgs: optional. Dict. kwargs for the client
                                    method call
                    - waitForField: mandatory. string. format expression for
                                    field name to check in awsClient response.
                    - toBe: mandatory. string. string. Stop waiting when
                            waitForField equals this value.
                    - pollInterval: optional. int. In seconds. Default to 30.
                    - maxAttempts: optional. int. Default 10.
                    - errorOnWaitTimeout: optional. Default True. Throws error
                                          if maxAttempts exhausted without
                                          reaching toBe value. If false,
                                          step completes without raising
                                          error.

    Returns: None
             Adds key to context:
            - awsWaitForTimedOut: bool. Adds key with value True if
              errorOnWaitTimeout=False and max_attempts exhausted without
              reaching toBe. If steps completes successfully and waitForField's
              value becomes toBe, awsWaitForTimedOut == False.

    Raises:
        pypyr.errors.KeyNotInContextError: awsWaitFor missing in context.
        pypyr.errors.KeyInContextHasNoValueError: awsWaitFor exists but is
                                                None.
        pypyraws.errors.WaitTimeOut: maxAttempts exceeded without waitForField
                                  changing to toBe.
    """
    logger.debug("started")
    context.assert_key_has_value('awsWaitFor', __name__)
    wait_for = context['awsWaitFor']

    client_in, service_name, method_name = contextargs.get_awsclient_args(
        wait_for, __name__)

    service_name = context.get_formatted_string(service_name)
    method_name = context.get_formatted_string(method_name)

    client_args = contextargs.get_formatted_iterable(input_dict=client_in,
                                                     field_name='clientArgs',
                                                     context=context)

    method_args = contextargs.get_formatted_iterable(input_dict=client_in,
                                                     field_name='methodArgs',
                                                     context=context)

    (wait_for_field, to_be, poll_interval, max_attempts,
     error_on_wait_timeout) = get_poll_args(wait_for, context)

    wait_response = wait_until_true(
        interval=poll_interval,
        max_attempts=max_attempts)(execute_aws_client_method)(
            service_name=service_name,
            method_name=method_name,
            client_args=client_args,
            method_args=method_args,
            wait_for_field=wait_for_field,
            to_be=to_be)

    if wait_response:
        context['awsWaitForTimedOut'] = False
        logger.info(f"aws {service_name} {method_name} returned {to_be}. "
                    "Pipeline will now continue.")
    else:
        if error_on_wait_timeout:
            context['awsWaitForTimedOut'] = True
            logger.error(f"aws {service_name} {method_name} did not return "
                         f"{to_be} within {max_attempts}. errorOnWaitTimeout "
                         "is True, throwing error")
            raise WaitTimeOut(f"aws {service_name} {method_name} did not "
                              f"return {to_be} within {max_attempts} retries.")
        else:
            context['awsWaitForTimedOut'] = True
            logger.warn(f"aws {service_name} {method_name} did NOT return "
                        f" {to_be}. errorOnWaitTimeout is False, so pipeline "
                        "will proceed to the next step anyway.")

    logger.debug("done")