From 1d21cec0004afae584e9c429238d402b888ae78c Mon Sep 17 00:00:00 2001 From: Sherman Hui <11592023+shermanhui@users.noreply.github.com> Date: Sun, 24 Oct 2021 12:35:54 -0700 Subject: [PATCH] feat: add describe_receipt_rule method to ses mock (#4458) --- IMPLEMENTATION_COVERAGE.md | 59 ++++++++++--------- moto/ses/exceptions.py | 7 +++ moto/ses/models.py | 15 ++++- moto/ses/responses.py | 59 ++++++++++++++++++- tests/test_ses/test_ses_boto3.py | 97 ++++++++++++++++++++++++++++++++ 5 files changed, 209 insertions(+), 28 deletions(-) diff --git a/IMPLEMENTATION_COVERAGE.md b/IMPLEMENTATION_COVERAGE.md index 7f48252aa..dd66433a4 100644 --- a/IMPLEMENTATION_COVERAGE.md +++ b/IMPLEMENTATION_COVERAGE.md @@ -590,7 +590,7 @@ ## cognito-idp
-49% implemented +50% implemented - [ ] add_custom_attributes - [X] admin_add_user_to_group @@ -688,7 +688,7 @@ - [X] update_identity_provider - [ ] update_resource_server - [ ] update_user_attributes -- [ ] update_user_pool +- [X] update_user_pool - [X] update_user_pool_client - [X] update_user_pool_domain - [X] verify_software_token @@ -1340,8 +1340,6 @@ - [ ] get_transit_gateway_prefix_list_references - [ ] get_transit_gateway_route_table_associations - [ ] get_transit_gateway_route_table_propagations -- [ ] get_vpn_connection_device_sample_configuration -- [ ] get_vpn_connection_device_types - [ ] import_client_vpn_client_certificate_revocation_list - [ ] import_image - [ ] import_instance @@ -1463,7 +1461,7 @@ ## ecr
-74% implemented +76% implemented - [ ] batch_check_layer_availability - [X] batch_delete_image @@ -1474,7 +1472,6 @@ - [X] delete_registry_policy - [X] delete_repository - [X] delete_repository_policy -- [ ] describe_image_replication_status - [X] describe_image_scan_findings - [X] describe_images - [X] describe_registry @@ -1504,13 +1501,13 @@ ## ecs
-67% implemented +73% implemented - [ ] create_capacity_provider - [X] create_cluster - [X] create_service - [X] create_task_set -- [ ] delete_account_setting +- [X] delete_account_setting - [X] delete_attributes - [ ] delete_capacity_provider - [X] delete_cluster @@ -1527,7 +1524,7 @@ - [X] describe_tasks - [ ] discover_poll_endpoint - [ ] execute_command -- [ ] list_account_settings +- [X] list_account_settings - [X] list_attributes - [X] list_clusters - [X] list_container_instances @@ -1536,7 +1533,7 @@ - [X] list_task_definition_families - [X] list_task_definitions - [X] list_tasks -- [ ] put_account_setting +- [X] put_account_setting - [ ] put_account_setting_default - [X] put_attributes - [ ] put_cluster_capacity_providers @@ -1595,7 +1592,7 @@ ## eks
-35% implemented +37% implemented - [ ] associate_encryption_config - [ ] associate_identity_provider_config @@ -1607,7 +1604,6 @@ - [X] delete_cluster - [X] delete_fargate_profile - [X] delete_nodegroup -- [ ] deregister_cluster - [ ] describe_addon - [ ] describe_addon_versions - [X] describe_cluster @@ -1623,7 +1619,6 @@ - [X] list_nodegroups - [ ] list_tags_for_resource - [ ] list_updates -- [ ] register_cluster - [ ] tag_resource - [ ] untag_resource - [ ] update_addon @@ -2521,7 +2516,6 @@ - [X] list_topic_rules - [ ] list_v2_logging_levels - [ ] list_violation_events -- [ ] put_verification_state_on_violation - [ ] register_ca_certificate - [X] register_certificate - [X] register_certificate_without_ca @@ -3711,7 +3705,6 @@ - [ ] create_presigned_notebook_instance_url - [ ] create_processing_job - [ ] create_project -- [ ] create_studio_lifecycle_config - [X] create_training_job - [ ] create_transform_job - [ ] create_trial @@ -3750,7 +3743,6 @@ - [X] delete_notebook_instance_lifecycle_config - [ ] delete_pipeline - [ ] delete_project -- [ ] delete_studio_lifecycle_config - [ ] delete_tags - [ ] delete_trial - [ ] delete_trial_component @@ -3796,7 +3788,6 @@ - [ ] describe_pipeline_execution - [ ] describe_processing_job - [ ] describe_project -- [ ] describe_studio_lifecycle_config - [ ] describe_subscribed_workteam - [X] describe_training_job - [ ] describe_transform_job @@ -3855,7 +3846,6 @@ - [ ] list_pipelines - [ ] list_processing_jobs - [ ] list_projects -- [ ] list_studio_lifecycle_configs - [ ] list_subscribed_workteams - [ ] list_tags - [X] list_training_jobs @@ -3869,7 +3859,6 @@ - [ ] put_model_package_group_policy - [ ] register_devices - [ ] render_ui_template -- [ ] retry_pipeline_execution - [ ] search - [ ] send_pipeline_execution_step_failure - [ ] send_pipeline_execution_step_success @@ -3943,7 +3932,7 @@ ## ses
-25% implemented +29% implemented - [ ] clone_receipt_rule_set - [X] create_configuration_set @@ -3967,13 +3956,13 @@ - [ ] delete_verified_email_address - [ ] describe_active_receipt_rule_set - [ ] describe_configuration_set -- [ ] describe_receipt_rule +- [X] describe_receipt_rule - [ ] describe_receipt_rule_set - [ ] get_account_sending_enabled - [ ] get_custom_verification_email_template - [ ] get_identity_dkim_attributes - [ ] get_identity_mail_from_domain_attributes -- [ ] get_identity_notification_attributes +- [X] get_identity_notification_attributes - [ ] get_identity_policies - [ ] get_identity_verification_attributes - [X] get_send_quota @@ -3998,7 +3987,7 @@ - [X] send_templated_email - [ ] set_active_receipt_rule_set - [ ] set_identity_dkim_enabled -- [ ] set_identity_feedback_forwarding_enabled +- [X] set_identity_feedback_forwarding_enabled - [ ] set_identity_headers_in_notifications_enabled - [ ] set_identity_mail_from_domain - [X] set_identity_notification_topic @@ -4336,6 +4325,27 @@ - [ ] untag_resource
+## timestream-write +
+80% implemented + +- [X] create_database +- [X] create_table +- [X] delete_database +- [X] delete_table +- [X] describe_database +- [X] describe_endpoints +- [X] describe_table +- [X] list_databases +- [X] list_tables +- [ ] list_tags_for_resource +- [ ] tag_resource +- [ ] untag_resource +- [X] update_database +- [X] update_table +- [X] write_records +
+ ## transcribe
41% implemented @@ -4536,7 +4546,6 @@ - iotwireless - ivs - kafka -- kafkaconnect - kendra - kinesis-video-media - kinesis-video-signaling @@ -4575,7 +4584,6 @@ - network-firewall - networkmanager - nimble -- opensearch - opsworkscm - outposts - personalize @@ -4630,7 +4638,6 @@ - synthetics - textract - timestream-query -- timestream-write - transfer - translate - waf diff --git a/moto/ses/exceptions.py b/moto/ses/exceptions.py index 7fdf9ec61..3a5d1fe48 100644 --- a/moto/ses/exceptions.py +++ b/moto/ses/exceptions.py @@ -88,6 +88,13 @@ class RuleSetDoesNotExist(RESTError): super(RuleSetDoesNotExist, self).__init__("RuleSetDoesNotExist", message) +class RuleDoesNotExist(RESTError): + code = 400 + + def __init__(self, message): + super(RuleDoesNotExist, self).__init__("RuleDoesNotExist", message) + + class MissingRenderingAttributeException(RESTError): code = 400 diff --git a/moto/ses/models.py b/moto/ses/models.py index b88086c21..478b72993 100644 --- a/moto/ses/models.py +++ b/moto/ses/models.py @@ -18,6 +18,7 @@ from .exceptions import ( InvalidParameterValue, InvalidRenderingParameterException, TemplateDoesNotExist, + RuleDoesNotExist, RuleSetNameAlreadyExists, RuleSetDoesNotExist, RuleAlreadyExists, @@ -413,7 +414,7 @@ class SESBackend(BaseBackend): def create_receipt_rule_set(self, rule_set_name): if self.receipt_rule_set.get(rule_set_name) is not None: - raise RuleSetNameAlreadyExists("Duplicate receipt rule set Name.") + raise RuleSetNameAlreadyExists("Duplicate Receipt Rule Set Name.") self.receipt_rule_set[rule_set_name] = [] def create_receipt_rule(self, rule_set_name, rule): @@ -425,5 +426,17 @@ class SESBackend(BaseBackend): rule_set.append(rule) self.receipt_rule_set[rule_set_name] = rule_set + def describe_receipt_rule(self, rule_set_name, rule_name): + rule_set = self.receipt_rule_set.get(rule_set_name) + + if rule_set is None: + raise RuleSetDoesNotExist("Invalid Rule Set Name.") + + for receipt_rule in rule_set: + if receipt_rule["name"] == rule_name: + return receipt_rule + else: + raise RuleDoesNotExist("Invalid Rule Name.") + ses_backend = SESBackend() diff --git a/moto/ses/responses.py b/moto/ses/responses.py index 73bc45398..43474cbf4 100644 --- a/moto/ses/responses.py +++ b/moto/ses/responses.py @@ -234,11 +234,25 @@ class EmailResponse(BaseResponse): def create_receipt_rule(self): rule_set_name = self._get_param("RuleSetName") - rule = self._get_dict_param("Rule") + rule = self._get_dict_param("Rule.") ses_backend.create_receipt_rule(rule_set_name, rule) template = self.response_template(CREATE_RECEIPT_RULE) return template.render() + def describe_receipt_rule(self): + rule_set_name = self._get_param("RuleSetName") + rule_name = self._get_param("RuleName") + + receipt_rule = ses_backend.describe_receipt_rule(rule_set_name, rule_name) + + rule = {} + + for k, v in receipt_rule.items(): + self._parse_param(k, v, rule) + + template = self.response_template(DESCRIBE_RECEIPT_RULE) + return template.render(rule=rule) + VERIFY_EMAIL_IDENTITY = """ @@ -492,3 +506,46 @@ CREATE_RECEIPT_RULE = """ + + + + {% for recipient in rule["recipients"] %} + {{recipient}} + {% endfor %} + + {{rule["name"]}} + + {% for action in rule["actions"] %} + + {% if action["_s3_action"] %} + + {{action["_s3_action"]["_bucket_name"]}} + {{action["_s3_action"]["_kms_key_arn"]}} + {{action["_s3_action"]["_object_key_prefix"]}} + {{action["_s3_action"]["_topic_arn"]}} + + {% endif %} + {% if action["_bounce_action"] %} + + {{action["_bounce_action"]["_topic_arn"]}} + {{action["_bounce_action"]["_smtp_reply_code"]}} + {{action["_bounce_action"]["_status_code"]}} + {{action["_bounce_action"]["_message"]}} + {{action["_bounce_action"]["_sender"]}} + + {% endif %} + + {% endfor %} + + {{rule["tls_policy"]}} + {{rule["scan_enabled"]}} + {{rule["enabled"]}} + + + + 15e0ef1a-9bf2-11e1-9279-01ab88cf109a + + +""" diff --git a/tests/test_ses/test_ses_boto3.py b/tests/test_ses/test_ses_boto3.py index dcb15cbd3..1ce32a1f2 100644 --- a/tests/test_ses/test_ses_boto3.py +++ b/tests/test_ses/test_ses_boto3.py @@ -481,6 +481,103 @@ def test_create_receipt_rule(): ex.value.response["Error"]["Code"].should.equal("RuleSetDoesNotExist") +@mock_ses +def test_describe_receipt_rule(): + conn = boto3.client("ses", region_name="us-east-1") + rule_set_name = "testRuleSet" + conn.create_receipt_rule_set(RuleSetName=rule_set_name) + + rule_name = "testRule" + conn.create_receipt_rule( + RuleSetName=rule_set_name, + Rule={ + "Name": rule_name, + "Enabled": False, + "TlsPolicy": "Optional", + "Recipients": ["test@email.com", "test2@email.com"], + "Actions": [ + { + "S3Action": { + "TopicArn": "string", + "BucketName": "testBucketName", + "ObjectKeyPrefix": "testObjectKeyPrefix", + "KmsKeyArn": "string", + }, + "BounceAction": { + "TopicArn": "string", + "SmtpReplyCode": "string", + "StatusCode": "string", + "Message": "string", + "Sender": "string", + }, + } + ], + "ScanEnabled": False, + }, + ) + + receipt_rule_response = conn.describe_receipt_rule( + RuleSetName=rule_set_name, RuleName=rule_name + ) + + receipt_rule_response["Rule"]["Name"].should.equal(rule_name) + + receipt_rule_response["Rule"]["Enabled"].should.equal(False) + + receipt_rule_response["Rule"]["TlsPolicy"].should.equal("Optional") + + len(receipt_rule_response["Rule"]["Recipients"]).should.equal(2) + receipt_rule_response["Rule"]["Recipients"][0].should.equal("test@email.com") + + len(receipt_rule_response["Rule"]["Actions"]).should.equal(1) + receipt_rule_response["Rule"]["Actions"][0].should.have.key("S3Action") + + receipt_rule_response["Rule"]["Actions"][0]["S3Action"].should.have.key( + "TopicArn" + ).being.equal("string") + receipt_rule_response["Rule"]["Actions"][0]["S3Action"].should.have.key( + "BucketName" + ).being.equal("testBucketName") + receipt_rule_response["Rule"]["Actions"][0]["S3Action"].should.have.key( + "ObjectKeyPrefix" + ).being.equal("testObjectKeyPrefix") + receipt_rule_response["Rule"]["Actions"][0]["S3Action"].should.have.key( + "KmsKeyArn" + ).being.equal("string") + + receipt_rule_response["Rule"]["Actions"][0].should.have.key("BounceAction") + + receipt_rule_response["Rule"]["Actions"][0]["BounceAction"].should.have.key( + "TopicArn" + ).being.equal("string") + receipt_rule_response["Rule"]["Actions"][0]["BounceAction"].should.have.key( + "SmtpReplyCode" + ).being.equal("string") + receipt_rule_response["Rule"]["Actions"][0]["BounceAction"].should.have.key( + "StatusCode" + ).being.equal("string") + receipt_rule_response["Rule"]["Actions"][0]["BounceAction"].should.have.key( + "Message" + ).being.equal("string") + receipt_rule_response["Rule"]["Actions"][0]["BounceAction"].should.have.key( + "Sender" + ).being.equal("string") + + receipt_rule_response["Rule"]["ScanEnabled"].should.equal(False) + + with pytest.raises(ClientError) as error: + conn.describe_receipt_rule(RuleSetName="invalidRuleSetName", RuleName=rule_name) + + error.value.response["Error"]["Code"].should.equal("RuleSetDoesNotExist") + + with pytest.raises(ClientError) as error: + conn.describe_receipt_rule( + RuleSetName=rule_set_name, RuleName="invalidRuleName" + ) + + error.value.response["Error"]["Code"].should.equal("RuleDoesNotExist") + + @mock_ses def test_create_ses_template(): conn = boto3.client("ses", region_name="us-east-1")