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()
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)
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
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
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 == {}
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()
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
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
def resource(): return Resource(TYPE_NAME, None)