Exemplo n.º 1
0
def test_test_entrypoint_success():
    mock_model = Mock(spec_set=["_deserialize"])
    mock_model._deserialize.side_effect = [None, None]

    resource = Resource(TYPE_NAME, mock_model)
    progress_event = ProgressEvent(status=OperationStatus.SUCCESS)
    mock_handler = resource.handler(Action.CREATE)(
        Mock(return_value=progress_event))

    payload = {
        "credentials": {
            "accessKeyId": "",
            "secretAccessKey": "",
            "sessionToken": ""
        },
        "action": "CREATE",
        "request": {
            "clientRequestToken": "ecba020e-b2e6-4742-a7d0-8a06ae7c4b2b",
            "desiredResourceState": None,
            "previousResourceState": None,
            "logicalResourceIdentifier": None,
        },
    }

    event = resource.test_entrypoint.__wrapped__(  # pylint: disable=no-member
        resource, payload, None)
    assert event is progress_event

    mock_model._deserialize.assert_has_calls([call(None), call(None)])
    mock_handler.assert_called_once()
Exemplo n.º 2
0
def test_entrypoint_success_without_caller_provider_creds():
    resource = Resource(TYPE_NAME, Mock())
    event = ProgressEvent(status=OperationStatus.SUCCESS, message="")
    resource.handler(Action.CREATE)(Mock(return_value=event))

    payload = ENTRYPOINT_PAYLOAD.copy()
    payload["requestData"] = payload["requestData"].copy()

    expected = {
        "message": "",
        "status": OperationStatus.SUCCESS,
        "callbackDelaySeconds": 0,
    }

    with patch(
            "cloudformation_cli_python_lib.resource.ProviderLogHandler.setup"):
        # Credentials are defined in payload, but null
        payload["requestData"]["providerCredentials"] = None
        payload["requestData"]["callerCredentials"] = None
        event = resource.__call__.__wrapped__(  # pylint: disable=no-member
            resource, payload, None)
        assert event == expected

        # Credentials are undefined in payload
        del payload["requestData"]["providerCredentials"]
        del payload["requestData"]["callerCredentials"]

        event = resource.__call__.__wrapped__(  # pylint: disable=no-member
            resource, payload, None)
        assert event == expected
def test__parse_request_fail_without_platform_creds():
    resource = Resource(TYPE_NAME, Mock())

    payload = ENTRYPOINT_PAYLOAD.copy()
    payload["requestData"] = payload["requestData"].copy()
    payload["requestData"]["platformCredentials"] = None

    with pytest.raises(InvalidRequest) as excinfo:
        resource._parse_request(payload)

    assert "ValueError" in str(excinfo.value)
Exemplo n.º 4
0
def test__parse_request_valid_request_and__cast_resource_request():
    mock_model = Mock(spec_set=["_deserialize"])
    mock_model._deserialize.side_effect = [
        sentinel.state_out1, sentinel.state_out2
    ]

    mock_type_configuration_model = Mock(spec_set=["_deserialize"])
    mock_type_configuration_model._deserialize.side_effect = [
        sentinel.type_configuration
    ]

    resource = Resource(TYPE_NAME, mock_model, mock_type_configuration_model)

    with patch("cloudformation_cli_python_lib.resource._get_boto_session"
               ) as mock_session:
        ret = resource._parse_request(ENTRYPOINT_PAYLOAD)
    sessions, action, callback_context, request = ret

    mock_session.assert_has_calls(
        [
            call(
                Credentials(
                    **ENTRYPOINT_PAYLOAD["requestData"]["callerCredentials"])),
            call(
                Credentials(**ENTRYPOINT_PAYLOAD["requestData"]
                            ["providerCredentials"])),
        ],
        any_order=True,
    )

    # credentials are used when rescheduling, so can't zero them out (for now)
    assert request.requestData.callerCredentials is not None
    assert request.requestData.providerCredentials is not None
    assert request.requestData.typeConfiguration is sentinel.type_configuration

    caller_sess, provider_sess = sessions
    assert caller_sess is mock_session.return_value
    assert provider_sess is mock_session.return_value

    assert action == Action.CREATE
    assert callback_context == {}

    modeled_request = resource._cast_resource_request(request)

    mock_model._deserialize.assert_has_calls(
        [call(sentinel.state_in1),
         call(sentinel.state_in2)])
    assert modeled_request.clientRequestToken == request.bearerToken
    assert modeled_request.desiredResourceState is sentinel.state_out1
    assert modeled_request.previousResourceState is sentinel.state_out2
    assert modeled_request.typeConfiguration is sentinel.type_configuration
    assert modeled_request.logicalResourceIdentifier == "myBucket"
    assert modeled_request.nextToken is None
Exemplo n.º 5
0
def test_entrypoint_non_mutating_action():
    payload = ENTRYPOINT_PAYLOAD.copy()
    payload["action"] = "READ"
    resource = Resource(TYPE_NAME, Mock())
    event = ProgressEvent(status=OperationStatus.SUCCESS, message="")
    resource.handler(Action.CREATE)(Mock(return_value=event))

    with patch(
            "cloudformation_cli_python_lib.resource.ProviderLogHandler.setup"
    ) as mock_return_progress:
        resource.__call__.__wrapped__(  # pylint: disable=no-member
            resource, payload, None)
    assert mock_return_progress.call_count == 1
Exemplo n.º 6
0
def test__parse_test_request_valid_request():
    mock_model = Mock(spec_set=["_deserialize"])
    mock_model._deserialize.side_effect = [
        sentinel.state_out1, sentinel.state_out2
    ]

    mock_type_configuration_model = Mock(spec_set=["_deserialize"])
    mock_type_configuration_model._deserialize.side_effect = [
        sentinel.type_configuration
    ]

    payload = {
        "credentials": {
            "accessKeyId": "",
            "secretAccessKey": "",
            "sessionToken": ""
        },
        "action": "CREATE",
        "request": {
            "clientRequestToken": "ecba020e-b2e6-4742-a7d0-8a06ae7c4b2b",
            "desiredResourceState": sentinel.state_in1,
            "previousResourceState": sentinel.state_in2,
            "logicalResourceIdentifier": None,
            "typeConfiguration": sentinel.type_configuration,
        },
        "callbackContext": None,
    }

    resource = Resource(TYPE_NAME, mock_model, mock_type_configuration_model)

    with patch("cloudformation_cli_python_lib.resource._get_boto_session"
               ) as mock_session:
        ret = resource._parse_test_request(payload)
    session, request, action, callback_context = ret

    mock_session.assert_called_once()
    assert session is mock_session.return_value

    assert request.clientRequestToken == "ecba020e-b2e6-4742-a7d0-8a06ae7c4b2b"
    mock_model._deserialize.assert_has_calls(
        [call(sentinel.state_in1),
         call(sentinel.state_in2)])
    assert request.desiredResourceState is sentinel.state_out1
    assert request.previousResourceState is sentinel.state_out2
    assert request.typeConfiguration is sentinel.type_configuration
    assert request.logicalResourceIdentifier is None

    assert action == Action.CREATE
    assert callback_context == {}
Exemplo n.º 7
0
def test_entrypoint_with_context():
    payload = ENTRYPOINT_PAYLOAD.copy()
    payload["callbackContext"] = {"a": "b"}
    resource = Resource(TYPE_NAME, Mock())
    event = ProgressEvent(status=OperationStatus.SUCCESS,
                          message="",
                          callbackContext={"c": "d"})
    mock_handler = resource.handler(Action.CREATE)(Mock(return_value=event))

    with patch(
            "cloudformation_cli_python_lib.resource.ProviderLogHandler.setup"):
        resource.__call__.__wrapped__(  # pylint: disable=no-member
            resource, payload, None)

    mock_handler.assert_called_once()
Exemplo n.º 8
0
def test_entrypoint_handler_raises():
    @dataclass
    class ResourceModel(BaseModel):
        a_string: str

        @classmethod
        def _deserialize(cls, json_data):
            return cls("test")

    resource = Resource(Mock(), ResourceModel)

    with patch(
            "cloudformation_cli_python_lib.resource.ProviderLogHandler.setup"
    ), patch(
            "cloudformation_cli_python_lib.resource.MetricsPublisherProxy"
    ) as mock_metrics, patch(
            "cloudformation_cli_python_lib.resource.Resource._invoke_handler"
    ) as mock__invoke_handler:
        mock__invoke_handler.side_effect = InvalidRequest("handler failed")
        event = resource.__call__.__wrapped__(  # pylint: disable=no-member
            resource, ENTRYPOINT_PAYLOAD, None)

    mock_metrics.return_value.publish_exception_metric.assert_called_once()
    assert event == {
        "errorCode": "InvalidRequest",
        "message": "handler failed",
        "status": "FAILED",
        "callbackDelaySeconds": 0,
    }
def test_schedule_reinvocation_cloudwatch_callback():
    progress = ProgressEvent(status=OperationStatus.IN_PROGRESS,
                             callbackDelaySeconds=60)
    mock_request = Mock(
        "cloudformation_cli_python_lib.interface.HandlerRequest",
        autospec=True)()
    mock_request.requestContext = {}
    mock_context = Mock(
        "cloudformation_cli_python_lib.interface.LambdaContext",
        autospec=True)()
    mock_context.get_remaining_time_in_millis.return_value = 6000
    mock_context.invoked_function_arn = "arn:aaa:bbb:ccc"
    with patch(
            "cloudformation_cli_python_lib.resource.reschedule_after_minutes",
            autospec=True) as mock_reschedule, patch(
                "cloudformation_cli_python_lib.resource.sleep",
                autospec=True) as mock_sleep:
        reinvoke = Resource.schedule_reinvocation(mock_request, progress,
                                                  mock_context, Mock())
    assert reinvoke is False
    mock_reschedule.assert_called_once_with(
        ANY,
        function_arn="arn:aaa:bbb:ccc",
        minutes_from_now=1,
        handler_request=mock_request,
    )
    mock_sleep.assert_not_called()
    assert mock_request.requestContext.get("invocation") == 1
Exemplo n.º 10
0
def test_entrypoint_success():
    resource = Resource(TYPE_NAME, Mock())
    event = ProgressEvent(status=OperationStatus.SUCCESS, message="")
    mock_handler = resource.handler(Action.CREATE)(Mock(return_value=event))

    with patch(
            "cloudformation_cli_python_lib.resource.ProviderLogHandler.setup"
    ) as mock_log_delivery:
        event = resource.__call__.__wrapped__(  # pylint: disable=no-member
            resource, ENTRYPOINT_PAYLOAD, None)
    mock_log_delivery.assert_called_once()

    assert event == {
        "message": "",
        "status": OperationStatus.SUCCESS.name,  # pylint: disable=no-member
        "callbackDelaySeconds": 0,
    }

    mock_handler.assert_called_once()
def test_entrypoint_success():
    resource = Resource(TYPE_NAME, Mock())
    event = ProgressEvent(status=OperationStatus.SUCCESS, message="")
    mock_handler = resource.handler(Action.CREATE)(Mock(return_value=event))

    with patch(
            "cloudformation_cli_python_lib.resource.ProviderLogHandler.setup"
    ) as mock_log_delivery, patch(
            "cloudformation_cli_python_lib.resource.report_progress",
            autospec=True) as mock_report_progress:
        event = resource.__call__.__wrapped__(  # pylint: disable=no-member
            resource, ENTRYPOINT_PAYLOAD, None)
    assert mock_report_progress.call_count == 2
    mock_log_delivery.assert_called_once()

    assert event == {
        "message": "",
        "bearerToken": "123456",
        "operationStatus": OperationStatus.SUCCESS.name,  # pylint: disable=no-member
    }

    mock_handler.assert_called_once()
def test_schedule_reinvocation_not_in_progress():
    progress = ProgressEvent(status=OperationStatus.SUCCESS)
    with patch(
            "cloudformation_cli_python_lib.resource._get_boto_session",
            autospec=True
    ) as mock_session, patch(
            "cloudformation_cli_python_lib.resource.reschedule_after_minutes",
            autospec=True) as mock_reschedule:
        reinvoke = Resource.schedule_reinvocation(sentinel.request, progress,
                                                  sentinel.context,
                                                  sentinel.session)
    assert reinvoke is False
    mock_session.assert_not_called()
    mock_reschedule.assert_not_called()
def test_schedule_reinvocation_local_callback():
    progress = ProgressEvent(status=OperationStatus.IN_PROGRESS,
                             callbackDelaySeconds=5)
    mock_request = Mock(
        "cloudformation_cli_python_lib.interface.HandlerRequest",
        autospec=True)()
    mock_request.requestContext = {}
    mock_context = Mock(
        "cloudformation_cli_python_lib.interface.LambdaContext",
        autospec=True)()
    mock_context.get_remaining_time_in_millis.return_value = 600000
    with patch("cloudformation_cli_python_lib.resource.sleep",
               autospec=True) as mock_sleep:
        reinvoke = Resource.schedule_reinvocation(mock_request, progress,
                                                  mock_context,
                                                  sentinel.session)
    assert reinvoke is True
    mock_sleep.assert_called_once_with(5)
    assert mock_request.requestContext.get("invocation") == 1
Exemplo n.º 14
0
def resource():
    return Resource(TYPE_NAME, None)