def test_assert_failed_callback_delay_seconds_set():
    with pytest.raises(AssertionError):
        HookClient.assert_failed(
            HookStatus.FAILED,
            {
                "errorCode": HandlerErrorCode.AccessDenied.value,
                "callbackDelaySeconds": 5,
            },
        )
def hook_client():
    endpoint = "https://"
    patch_sesh = patch("rpdk.core.contract.hook_client.create_sdk_session",
                       autospec=True)
    patch_creds = patch(
        "rpdk.core.contract.hook_client.get_temporary_credentials",
        autospec=True,
        return_value={},
    )
    patch_account = patch(
        "rpdk.core.contract.hook_client.get_account",
        autospec=True,
        return_value=ACCOUNT,
    )
    with patch_sesh as mock_create_sesh, patch_creds as mock_creds:
        with patch_account as mock_account:
            mock_sesh = mock_create_sesh.return_value
            mock_sesh.region_name = DEFAULT_REGION
            client = HookClient(DEFAULT_FUNCTION, endpoint, DEFAULT_REGION,
                                SCHEMA_, EMPTY_OVERRIDE)

    mock_sesh.client.assert_called_once_with("lambda", endpoint_url=endpoint)
    mock_creds.assert_called_once_with(mock_sesh, LOWER_CAMEL_CRED_KEYS, None)
    mock_account.assert_called_once_with(mock_sesh, {})
    assert client._function_name == DEFAULT_FUNCTION
    assert client._schema == SCHEMA_
    assert client._configuration_schema == SCHEMA_["typeConfiguration"]
    assert client._overrides == EMPTY_OVERRIDE
    assert client.account == ACCOUNT

    return client
def test_init_sam_cli_client():
    patch_sesh = patch("rpdk.core.contract.hook_client.create_sdk_session",
                       autospec=True)
    patch_creds = patch(
        "rpdk.core.contract.hook_client.get_temporary_credentials",
        autospec=True,
        return_value={},
    )
    patch_account = patch(
        "rpdk.core.contract.hook_client.get_account",
        autospec=True,
        return_value=ACCOUNT,
    )
    with patch_sesh as mock_create_sesh, patch_creds as mock_creds:
        with patch_account as mock_account:
            mock_sesh = mock_create_sesh.return_value
            mock_sesh.region_name = DEFAULT_REGION
            client = HookClient(DEFAULT_FUNCTION, DEFAULT_ENDPOINT,
                                DEFAULT_REGION, {}, EMPTY_OVERRIDE)

    mock_sesh.client.assert_called_once_with("lambda",
                                             endpoint_url=DEFAULT_ENDPOINT,
                                             use_ssl=False,
                                             verify=False,
                                             config=ANY)
    mock_creds.assert_called_once_with(mock_sesh, LOWER_CAMEL_CRED_KEYS, None)
    mock_account.assert_called_once_with(mock_sesh, {})
    assert client.account == ACCOUNT
def test_generate_example(hook_client):
    hook_target_info = {
        "AWS::Example::Target": {
            "TypeName": "AWS::Example::Target",
            "Schema": {
                "properties": {
                    "a": {
                        "type": "number",
                        "const": 1
                    },
                    "b": {
                        "type": "number",
                        "const": 2
                    },
                },
                "readOnlyProperties": ["/properties/b"],
            },
        }
    }
    hook_client._target_info = HookClient._setup_target_info(hook_target_info)
    assert not hook_client._target_info["AWS::Example::Target"].get(
        "SchemaStrategy")

    example = hook_client._generate_target_example("AWS::Example::Target")
    assert example == {"a": 1}
    assert hook_client._target_info["AWS::Example::Target"]["SchemaStrategy"]
def test_generate_update_example(hook_client):
    hook_target_info = {
        "AWS::Example::Target": {
            "TypeName": "AWS::Example::Target",
            "Schema": {
                "properties": {
                    "a": {
                        "type": "number",
                        "const": 1
                    },
                    "b": {
                        "type": "number",
                        "const": 2
                    },
                    "c": {
                        "type": "number",
                        "const": 3
                    },
                },
                "readOnlyProperties": ["/properties/b"],
                "createOnlyProperties": ["/properties/c"],
            },
        }
    }
    hook_client._target_info = HookClient._setup_target_info(hook_target_info)
    hook_client._overrides = {}
    assert not hook_client._target_info["AWS::Example::Target"].get(
        "UpdateSchemaStrategy")

    model = {"b": 2, "a": 4}
    example = hook_client._generate_target_update_example(
        "AWS::Example::Target", model)
    assert example == {"a": 1, "b": 2}
    assert hook_client._target_info["AWS::Example::Target"][
        "UpdateSchemaStrategy"]
def test_call_docker():
    patch_sesh = patch("rpdk.core.contract.hook_client.create_sdk_session",
                       autospec=True)
    patch_creds = patch(
        "rpdk.core.contract.hook_client.get_temporary_credentials",
        autospec=True,
        return_value={},
    )
    patch_config = patch(
        "rpdk.core.contract.hook_client.TypeConfiguration.get_hook_configuration",
        return_value={},
    )
    patch_account = patch(
        "rpdk.core.contract.hook_client.get_account",
        autospec=True,
        return_value=ACCOUNT,
    )
    patch_docker = patch("rpdk.core.contract.hook_client.docker",
                         autospec=True)
    with patch_sesh as mock_create_sesh, patch_docker as mock_docker, patch_creds, patch_config:
        with patch_account:
            mock_client = mock_docker.from_env.return_value
            mock_sesh = mock_create_sesh.return_value
            mock_sesh.region_name = DEFAULT_REGION
            hook_client = HookClient(
                DEFAULT_FUNCTION,
                "url",
                DEFAULT_REGION,
                {},
                EMPTY_OVERRIDE,
                docker_image="docker_image",
                executable_entrypoint="entrypoint",
            )
            hook_client._type_name = HOOK_TYPE_NAME
    response_str = ("__CFN_HOOK_START_RESPONSE__"
                    '{"hookStatus": "SUCCESS"}__CFN_HOOK_END_RESPONSE__')
    mock_client.containers.run.return_value = str.encode(response_str)
    with patch_creds:
        status, response = hook_client.call("CREATE_PRE_PROVISION",
                                            HOOK_TARGET_TYPE_NAME,
                                            {"foo": "bar"})

    mock_client.containers.run.assert_called_once()
    assert status == HookStatus.SUCCESS
    assert response == {"hookStatus": HookStatus.SUCCESS.value}
def test_assert_failed_returns_error_code():
    error_code = HookClient.assert_failed(
        HookStatus.FAILED,
        {
            "errorCode": HandlerErrorCode.AccessDenied.value,
            "message": "I have failed you",
        },
    )
    assert error_code == HandlerErrorCode.AccessDenied
def test_call_docker_executable_entrypoint_null():
    TypeConfiguration.TYPE_CONFIGURATION = {}
    patch_sesh = patch("rpdk.core.contract.hook_client.create_sdk_session",
                       autospec=True)
    patch_creds = patch(
        "rpdk.core.contract.hook_client.get_temporary_credentials",
        autospec=True,
        return_value={},
    )
    patch_config = patch(
        "rpdk.core.contract.hook_client.TypeConfiguration.get_hook_configuration",
        return_value={},
    )
    patch_account = patch(
        "rpdk.core.contract.hook_client.get_account",
        autospec=True,
        return_value=ACCOUNT,
    )
    patch_docker = patch("rpdk.core.contract.hook_client.docker",
                         autospec=True)
    with patch_sesh as mock_create_sesh, patch_docker, patch_creds, patch_config:
        with patch_account:
            mock_sesh = mock_create_sesh.return_value
            mock_sesh.region_name = DEFAULT_REGION
            hook_client = HookClient(
                DEFAULT_FUNCTION,
                "url",
                DEFAULT_REGION,
                {},
                EMPTY_OVERRIDE,
                docker_image="docker_image",
            )
            hook_client._type_name = HOOK_TYPE_NAME

    try:
        with patch_creds:
            hook_client.call("CREATE_PRE_PROVISION", HOOK_TARGET_TYPE_NAME,
                             {"foo": "bar"})
    except InvalidProjectError:
        pass
    TypeConfiguration.TYPE_CONFIGURATION = None
def test_hook_success(hook_client, invocation_point, target, target_model):
    if HookClient.is_update_invocation_point(invocation_point):
        raise ValueError(
            "Invocation point {} not supported for this testing operation".format(
                invocation_point
            )
        )

    _status, response, _error_code = hook_client.call_and_assert(
        invocation_point, HookStatus.SUCCESS, target, target_model
    )

    return response
def test_hook_handlers_success(hook_client, invocation_point):
    is_update_hook = HookClient.is_update_invocation_point(invocation_point)
    for (
        _invocation_point,
        target,
        target_model,
    ) in hook_client.generate_request_examples(invocation_point):
        if is_update_hook:
            test_update_hook_success(
                hook_client, invocation_point, target, target_model
            )
        else:
            test_hook_success(hook_client, invocation_point, target, target_model)
def test_setup_target_info():
    hook_target_info = {
        "AWS::Example::Target": {
            "TypeName": "AWS::Example::Target",
            "Schema": TARGET_SCHEMA,
        }
    }

    target_info = HookClient._setup_target_info(hook_target_info)

    assert target_info["AWS::Example::Target"]["readOnlyProperties"] == {
        ("properties", "b")
    }
    assert target_info["AWS::Example::Target"]["createOnlyProperties"] == {
        ("properties", "c")
    }
def test_make_request(hook_type, log_group_name, log_creds):
    target_model = object()
    token = object()
    request = HookClient.make_request(
        HOOK_TARGET_TYPE_NAME,
        hook_type,
        ACCOUNT,
        "CREATE_PRE_PROVISION",
        {},
        log_group_name,
        log_creds,
        token,
        target_model,
        "00000001",
        "RESOURCE",
    )

    expected_request = {
        "requestData": {
            "callerCredentials": json.dumps({}),
            "targetName": HOOK_TARGET_TYPE_NAME,
            "targetLogicalId": token,
            "targetModel": target_model,
            "targetType": "RESOURCE",
        },
        "requestContext": {
            "callbackContext": None
        },
        "hookTypeName": hook_type,
        "hookTypeVersion": "00000001",
        "clientRequestToken": token,
        "stackId": token,
        "awsAccountId": ACCOUNT,
        "actionInvocationPoint": "CREATE_PRE_PROVISION",
        "hookModel": None,
    }
    if log_group_name and log_creds:
        expected_request["requestData"]["providerCredentials"] = json.dumps(
            log_creds)
        expected_request["requestData"][
            "providerLogGroupName"] = log_group_name
    assert request == expected_request
Ejemplo n.º 13
0
def get_contract_plugin_client(args, project, overrides, inputs):
    plugin_clients = {}
    if project.artifact_type == ARTIFACT_TYPE_HOOK:
        plugin_clients["hook_client"] = HookClient(
            args.function_name,
            args.endpoint,
            args.region,
            project.schema,
            overrides,
            inputs,
            args.role_arn,
            args.enforce_timeout,
            project.type_name,
            args.log_group_name,
            args.log_role_arn,
            executable_entrypoint=project.executable_entrypoint,
            docker_image=args.docker_image,
            target_info=project._load_target_info(  # pylint: disable=protected-access
                args.cloudformation_endpoint_url, args.region),
        )
        LOG.debug("Setup plugin for HOOK type")
        return plugin_clients

    plugin_clients["resource_client"] = ResourceClient(
        args.function_name,
        args.endpoint,
        args.region,
        project.schema,
        overrides,
        inputs,
        args.role_arn,
        args.enforce_timeout,
        project.type_name,
        args.log_group_name,
        args.log_role_arn,
        executable_entrypoint=project.executable_entrypoint,
        docker_image=args.docker_image,
    )
    LOG.debug("Setup plugin for RESOURCE type")
    return plugin_clients
def test_generate_token():
    token = HookClient.generate_token()
    assert isinstance(token, str)
    assert len(token) == 36
def test_assert_in_progress_callback_delay_seconds_unset():
    callback_delay_seconds = HookClient.assert_in_progress(
        HookStatus.IN_PROGRESS, {"result": None})
    assert callback_delay_seconds == 0
def hook_client_inputs():
    endpoint = "https://"
    patch_sesh = patch("rpdk.core.contract.hook_client.create_sdk_session",
                       autospec=True)
    patch_creds = patch(
        "rpdk.core.contract.hook_client.get_temporary_credentials",
        autospec=True,
        return_value={},
    )
    patch_account = patch(
        "rpdk.core.contract.hook_client.get_account",
        autospec=True,
        return_value=ACCOUNT,
    )
    with patch_sesh as mock_create_sesh, patch_creds as mock_creds:
        with patch_account as mock_account:
            mock_sesh = mock_create_sesh.return_value
            mock_sesh.region_name = DEFAULT_REGION
            client = HookClient(
                DEFAULT_FUNCTION,
                endpoint,
                DEFAULT_REGION,
                SCHEMA_,
                EMPTY_OVERRIDE,
                {
                    "CREATE_PRE_PROVISION": {
                        "My::Example::Resource": {
                            "resourceProperties": {
                                "a": 1
                            }
                        }
                    },
                    "UPDATE_PRE_PROVISION": {
                        "My::Example::Resource": {
                            "resourceProperties": {
                                "a": 2
                            },
                            "previousResourceProperties": {
                                "c": 4
                            },
                        }
                    },
                    "INVALID_DELETE_PRE_PROVISION": {
                        "My::Example::Resource": {
                            "resourceProperties": {
                                "b": 2
                            }
                        }
                    },
                    "INVALID": {
                        "My::Example::Resource": {
                            "resourceProperties": {
                                "b": 1
                            }
                        }
                    },
                },
                target_info=HOOK_TARGET_INFO,
            )

    mock_sesh.client.assert_called_once_with("lambda", endpoint_url=endpoint)
    mock_creds.assert_called_once_with(mock_sesh, LOWER_CAMEL_CRED_KEYS, None)
    mock_account.assert_called_once_with(mock_sesh, {})
    assert client._function_name == DEFAULT_FUNCTION
    assert client._schema == SCHEMA_
    assert client._configuration_schema == SCHEMA_["typeConfiguration"]
    assert client._overrides == EMPTY_OVERRIDE
    assert client.account == ACCOUNT

    return client
def test_assert_success_callback_delay_seconds_set():
    with pytest.raises(AssertionError):
        HookClient.assert_success(HookStatus.SUCCESS,
                                  {"callbackDelaySeconds": 5})
def test_is_update_invocation_point_true(invoke_point):
    assert HookClient.is_update_invocation_point(invoke_point)
def test_assert_success_wrong_status(status):
    with pytest.raises(AssertionError):
        HookClient.assert_success(status, {})
def test_assert_failed_error_code_invalid():
    with pytest.raises(KeyError):
        HookClient.assert_failed(HookStatus.FAILED, {"errorCode": "XXX"})
def test_assert_failed_error_code_unset():
    with pytest.raises(AssertionError):
        HookClient.assert_failed(HookStatus.FAILED, {})
def test_assert_failed_wrong_status(status):
    with pytest.raises(AssertionError):
        HookClient.assert_failed(status, {})
def test_assert_in_progress_result_set():
    with pytest.raises(AssertionError):
        HookClient.assert_in_progress(HookStatus.IN_PROGRESS, {"result": ""})
def test_assert_in_progress_error_code_set():
    with pytest.raises(AssertionError):
        HookClient.assert_in_progress(
            HookStatus.IN_PROGRESS,
            {"errorCode": HandlerErrorCode.AccessDenied.value},
        )
def test_is_update_invocation_point_false(invoke_point):
    assert not HookClient.is_update_invocation_point(invoke_point)
def test_assert_in_progress_callback_delay_seconds_set():
    callback_delay_seconds = HookClient.assert_in_progress(
        HookStatus.IN_PROGRESS, {"callbackDelaySeconds": 5})
    assert callback_delay_seconds == 5
def test_assert_success_error_code_set():
    with pytest.raises(AssertionError):
        HookClient.assert_success(
            HookStatus.SUCCESS,
            {"errorCode": HandlerErrorCode.AccessDenied.value})