SES v2 (#6259)
* feat: add ses v2 * feat: move wrap v1 logic into v2 api * feat: v2 api on v2 url * chore: types * chore: linting * feat: raw emails * chore: linting * feat: add list_contacts * fix: urls need to be explicit for this to work with moto server * chore: linting * chore: remodel * chore: rework * chore: cleanup * chore: fix test * chore: sort out mypy * feat: add contact lists * fix: new url for server mode * feat: create and delete * chore: linting * chore: linting * chore: refactor * chore: match errors with real responses * chore: linting * chore: run implementation coverage script * refactor: easier, faster look ups with dicts * refactor: contact is now a child of contactlist * tests: contactlists return 200 if empty, contacts do not * chore: update botocore and run implementation coverage script * refactor: add matching *_contact methods to backend model so coverage script can detect them
This commit is contained in:
parent
65cf66dbcf
commit
6f170410e8
@ -358,11 +358,13 @@
|
|||||||
|
|
||||||
## athena
|
## athena
|
||||||
<details>
|
<details>
|
||||||
<summary>26% implemented</summary>
|
<summary>23% implemented</summary>
|
||||||
|
|
||||||
- [ ] batch_get_named_query
|
- [ ] batch_get_named_query
|
||||||
- [ ] batch_get_prepared_statement
|
- [ ] batch_get_prepared_statement
|
||||||
- [ ] batch_get_query_execution
|
- [ ] batch_get_query_execution
|
||||||
|
- [ ] cancel_capacity_reservation
|
||||||
|
- [ ] create_capacity_reservation
|
||||||
- [X] create_data_catalog
|
- [X] create_data_catalog
|
||||||
- [X] create_named_query
|
- [X] create_named_query
|
||||||
- [ ] create_notebook
|
- [ ] create_notebook
|
||||||
@ -378,6 +380,8 @@
|
|||||||
- [ ] get_calculation_execution
|
- [ ] get_calculation_execution
|
||||||
- [ ] get_calculation_execution_code
|
- [ ] get_calculation_execution_code
|
||||||
- [ ] get_calculation_execution_status
|
- [ ] get_calculation_execution_status
|
||||||
|
- [ ] get_capacity_assignment_configuration
|
||||||
|
- [ ] get_capacity_reservation
|
||||||
- [X] get_data_catalog
|
- [X] get_data_catalog
|
||||||
- [ ] get_database
|
- [ ] get_database
|
||||||
- [X] get_named_query
|
- [X] get_named_query
|
||||||
@ -393,6 +397,7 @@
|
|||||||
- [ ] import_notebook
|
- [ ] import_notebook
|
||||||
- [ ] list_application_dpu_sizes
|
- [ ] list_application_dpu_sizes
|
||||||
- [ ] list_calculation_executions
|
- [ ] list_calculation_executions
|
||||||
|
- [ ] list_capacity_reservations
|
||||||
- [X] list_data_catalogs
|
- [X] list_data_catalogs
|
||||||
- [ ] list_databases
|
- [ ] list_databases
|
||||||
- [ ] list_engine_versions
|
- [ ] list_engine_versions
|
||||||
@ -406,6 +411,7 @@
|
|||||||
- [ ] list_table_metadata
|
- [ ] list_table_metadata
|
||||||
- [ ] list_tags_for_resource
|
- [ ] list_tags_for_resource
|
||||||
- [X] list_work_groups
|
- [X] list_work_groups
|
||||||
|
- [ ] put_capacity_assignment_configuration
|
||||||
- [ ] start_calculation_execution
|
- [ ] start_calculation_execution
|
||||||
- [X] start_query_execution
|
- [X] start_query_execution
|
||||||
- [ ] start_session
|
- [ ] start_session
|
||||||
@ -414,6 +420,7 @@
|
|||||||
- [ ] tag_resource
|
- [ ] tag_resource
|
||||||
- [ ] terminate_session
|
- [ ] terminate_session
|
||||||
- [ ] untag_resource
|
- [ ] untag_resource
|
||||||
|
- [ ] update_capacity_reservation
|
||||||
- [ ] update_data_catalog
|
- [ ] update_data_catalog
|
||||||
- [ ] update_named_query
|
- [ ] update_named_query
|
||||||
- [ ] update_notebook
|
- [ ] update_notebook
|
||||||
@ -1453,8 +1460,9 @@
|
|||||||
|
|
||||||
## datasync
|
## datasync
|
||||||
<details>
|
<details>
|
||||||
<summary>13% implemented</summary>
|
<summary>10% implemented</summary>
|
||||||
|
|
||||||
|
- [ ] add_storage_system
|
||||||
- [X] cancel_task_execution
|
- [X] cancel_task_execution
|
||||||
- [ ] create_agent
|
- [ ] create_agent
|
||||||
- [ ] create_location_efs
|
- [ ] create_location_efs
|
||||||
@ -1472,6 +1480,7 @@
|
|||||||
- [X] delete_location
|
- [X] delete_location
|
||||||
- [X] delete_task
|
- [X] delete_task
|
||||||
- [ ] describe_agent
|
- [ ] describe_agent
|
||||||
|
- [ ] describe_discovery_job
|
||||||
- [ ] describe_location_efs
|
- [ ] describe_location_efs
|
||||||
- [ ] describe_location_fsx_lustre
|
- [ ] describe_location_fsx_lustre
|
||||||
- [ ] describe_location_fsx_ontap
|
- [ ] describe_location_fsx_ontap
|
||||||
@ -1482,21 +1491,32 @@
|
|||||||
- [ ] describe_location_object_storage
|
- [ ] describe_location_object_storage
|
||||||
- [ ] describe_location_s3
|
- [ ] describe_location_s3
|
||||||
- [ ] describe_location_smb
|
- [ ] describe_location_smb
|
||||||
|
- [ ] describe_storage_system
|
||||||
|
- [ ] describe_storage_system_resource_metrics
|
||||||
|
- [ ] describe_storage_system_resources
|
||||||
- [ ] describe_task
|
- [ ] describe_task
|
||||||
- [ ] describe_task_execution
|
- [ ] describe_task_execution
|
||||||
|
- [ ] generate_recommendations
|
||||||
- [ ] list_agents
|
- [ ] list_agents
|
||||||
|
- [ ] list_discovery_jobs
|
||||||
- [ ] list_locations
|
- [ ] list_locations
|
||||||
|
- [ ] list_storage_systems
|
||||||
- [ ] list_tags_for_resource
|
- [ ] list_tags_for_resource
|
||||||
- [ ] list_task_executions
|
- [ ] list_task_executions
|
||||||
- [ ] list_tasks
|
- [ ] list_tasks
|
||||||
|
- [ ] remove_storage_system
|
||||||
|
- [ ] start_discovery_job
|
||||||
- [X] start_task_execution
|
- [X] start_task_execution
|
||||||
|
- [ ] stop_discovery_job
|
||||||
- [ ] tag_resource
|
- [ ] tag_resource
|
||||||
- [ ] untag_resource
|
- [ ] untag_resource
|
||||||
- [ ] update_agent
|
- [ ] update_agent
|
||||||
|
- [ ] update_discovery_job
|
||||||
- [ ] update_location_hdfs
|
- [ ] update_location_hdfs
|
||||||
- [ ] update_location_nfs
|
- [ ] update_location_nfs
|
||||||
- [ ] update_location_object_storage
|
- [ ] update_location_object_storage
|
||||||
- [ ] update_location_smb
|
- [ ] update_location_smb
|
||||||
|
- [ ] update_storage_system
|
||||||
- [X] update_task
|
- [X] update_task
|
||||||
- [ ] update_task_execution
|
- [ ] update_task_execution
|
||||||
</details>
|
</details>
|
||||||
@ -2831,7 +2851,7 @@
|
|||||||
|
|
||||||
## emr-containers
|
## emr-containers
|
||||||
<details>
|
<details>
|
||||||
<summary>42% implemented</summary>
|
<summary>40% implemented</summary>
|
||||||
|
|
||||||
- [X] cancel_job_run
|
- [X] cancel_job_run
|
||||||
- [ ] create_job_template
|
- [ ] create_job_template
|
||||||
@ -2844,6 +2864,7 @@
|
|||||||
- [ ] describe_job_template
|
- [ ] describe_job_template
|
||||||
- [ ] describe_managed_endpoint
|
- [ ] describe_managed_endpoint
|
||||||
- [X] describe_virtual_cluster
|
- [X] describe_virtual_cluster
|
||||||
|
- [ ] get_managed_endpoint_session_credentials
|
||||||
- [X] list_job_runs
|
- [X] list_job_runs
|
||||||
- [ ] list_job_templates
|
- [ ] list_job_templates
|
||||||
- [ ] list_managed_endpoints
|
- [ ] list_managed_endpoints
|
||||||
@ -3121,7 +3142,7 @@
|
|||||||
|
|
||||||
## glue
|
## glue
|
||||||
<details>
|
<details>
|
||||||
<summary>26% implemented</summary>
|
<summary>30% implemented</summary>
|
||||||
|
|
||||||
- [X] batch_create_partition
|
- [X] batch_create_partition
|
||||||
- [ ] batch_delete_connection
|
- [ ] batch_delete_connection
|
||||||
@ -3135,7 +3156,7 @@
|
|||||||
- [ ] batch_get_dev_endpoints
|
- [ ] batch_get_dev_endpoints
|
||||||
- [X] batch_get_jobs
|
- [X] batch_get_jobs
|
||||||
- [X] batch_get_partition
|
- [X] batch_get_partition
|
||||||
- [ ] batch_get_triggers
|
- [X] batch_get_triggers
|
||||||
- [ ] batch_get_workflows
|
- [ ] batch_get_workflows
|
||||||
- [ ] batch_stop_job_run
|
- [ ] batch_stop_job_run
|
||||||
- [X] batch_update_partition
|
- [X] batch_update_partition
|
||||||
@ -3162,7 +3183,7 @@
|
|||||||
- [ ] create_security_configuration
|
- [ ] create_security_configuration
|
||||||
- [ ] create_session
|
- [ ] create_session
|
||||||
- [X] create_table
|
- [X] create_table
|
||||||
- [ ] create_trigger
|
- [X] create_trigger
|
||||||
- [ ] create_user_defined_function
|
- [ ] create_user_defined_function
|
||||||
- [ ] create_workflow
|
- [ ] create_workflow
|
||||||
- [ ] delete_blueprint
|
- [ ] delete_blueprint
|
||||||
@ -3187,7 +3208,7 @@
|
|||||||
- [ ] delete_session
|
- [ ] delete_session
|
||||||
- [X] delete_table
|
- [X] delete_table
|
||||||
- [X] delete_table_version
|
- [X] delete_table_version
|
||||||
- [ ] delete_trigger
|
- [X] delete_trigger
|
||||||
- [ ] delete_user_defined_function
|
- [ ] delete_user_defined_function
|
||||||
- [ ] delete_workflow
|
- [ ] delete_workflow
|
||||||
- [ ] get_blueprint
|
- [ ] get_blueprint
|
||||||
@ -3244,8 +3265,8 @@
|
|||||||
- [X] get_table_versions
|
- [X] get_table_versions
|
||||||
- [X] get_tables
|
- [X] get_tables
|
||||||
- [X] get_tags
|
- [X] get_tags
|
||||||
- [ ] get_trigger
|
- [X] get_trigger
|
||||||
- [ ] get_triggers
|
- [X] get_triggers
|
||||||
- [ ] get_unfiltered_partition_metadata
|
- [ ] get_unfiltered_partition_metadata
|
||||||
- [ ] get_unfiltered_partitions_metadata
|
- [ ] get_unfiltered_partitions_metadata
|
||||||
- [ ] get_unfiltered_table_metadata
|
- [ ] get_unfiltered_table_metadata
|
||||||
@ -3272,7 +3293,7 @@
|
|||||||
- [ ] list_schemas
|
- [ ] list_schemas
|
||||||
- [ ] list_sessions
|
- [ ] list_sessions
|
||||||
- [ ] list_statements
|
- [ ] list_statements
|
||||||
- [ ] list_triggers
|
- [X] list_triggers
|
||||||
- [ ] list_workflows
|
- [ ] list_workflows
|
||||||
- [ ] put_data_catalog_encryption_settings
|
- [ ] put_data_catalog_encryption_settings
|
||||||
- [ ] put_resource_policy
|
- [ ] put_resource_policy
|
||||||
@ -3295,12 +3316,12 @@
|
|||||||
- [X] start_job_run
|
- [X] start_job_run
|
||||||
- [ ] start_ml_evaluation_task_run
|
- [ ] start_ml_evaluation_task_run
|
||||||
- [ ] start_ml_labeling_set_generation_task_run
|
- [ ] start_ml_labeling_set_generation_task_run
|
||||||
- [ ] start_trigger
|
- [X] start_trigger
|
||||||
- [ ] start_workflow_run
|
- [ ] start_workflow_run
|
||||||
- [X] stop_crawler
|
- [X] stop_crawler
|
||||||
- [ ] stop_crawler_schedule
|
- [ ] stop_crawler_schedule
|
||||||
- [ ] stop_session
|
- [ ] stop_session
|
||||||
- [ ] stop_trigger
|
- [X] stop_trigger
|
||||||
- [ ] stop_workflow_run
|
- [ ] stop_workflow_run
|
||||||
- [X] tag_resource
|
- [X] tag_resource
|
||||||
- [X] untag_resource
|
- [X] untag_resource
|
||||||
@ -3482,6 +3503,7 @@
|
|||||||
- [ ] list_publishing_destinations
|
- [ ] list_publishing_destinations
|
||||||
- [ ] list_tags_for_resource
|
- [ ] list_tags_for_resource
|
||||||
- [ ] list_threat_intel_sets
|
- [ ] list_threat_intel_sets
|
||||||
|
- [ ] start_malware_scan
|
||||||
- [ ] start_monitoring_members
|
- [ ] start_monitoring_members
|
||||||
- [ ] stop_monitoring_members
|
- [ ] stop_monitoring_members
|
||||||
- [ ] tag_resource
|
- [ ] tag_resource
|
||||||
@ -4863,7 +4885,7 @@
|
|||||||
|
|
||||||
## pinpoint
|
## pinpoint
|
||||||
<details>
|
<details>
|
||||||
<summary>10% implemented</summary>
|
<summary>9% implemented</summary>
|
||||||
|
|
||||||
- [X] create_app
|
- [X] create_app
|
||||||
- [ ] create_campaign
|
- [ ] create_campaign
|
||||||
@ -4932,6 +4954,9 @@
|
|||||||
- [ ] get_journey_date_range_kpi
|
- [ ] get_journey_date_range_kpi
|
||||||
- [ ] get_journey_execution_activity_metrics
|
- [ ] get_journey_execution_activity_metrics
|
||||||
- [ ] get_journey_execution_metrics
|
- [ ] get_journey_execution_metrics
|
||||||
|
- [ ] get_journey_run_execution_activity_metrics
|
||||||
|
- [ ] get_journey_run_execution_metrics
|
||||||
|
- [ ] get_journey_runs
|
||||||
- [ ] get_push_template
|
- [ ] get_push_template
|
||||||
- [ ] get_recommender_configuration
|
- [ ] get_recommender_configuration
|
||||||
- [ ] get_recommender_configurations
|
- [ ] get_recommender_configurations
|
||||||
@ -6412,6 +6437,98 @@
|
|||||||
- [X] verify_email_identity
|
- [X] verify_email_identity
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
## sesv2
|
||||||
|
<details>
|
||||||
|
<summary>10% implemented</summary>
|
||||||
|
|
||||||
|
- [ ] batch_get_metric_data
|
||||||
|
- [ ] create_configuration_set
|
||||||
|
- [ ] create_configuration_set_event_destination
|
||||||
|
- [X] create_contact
|
||||||
|
- [X] create_contact_list
|
||||||
|
- [ ] create_custom_verification_email_template
|
||||||
|
- [ ] create_dedicated_ip_pool
|
||||||
|
- [ ] create_deliverability_test_report
|
||||||
|
- [ ] create_email_identity
|
||||||
|
- [ ] create_email_identity_policy
|
||||||
|
- [ ] create_email_template
|
||||||
|
- [ ] create_import_job
|
||||||
|
- [ ] delete_configuration_set
|
||||||
|
- [ ] delete_configuration_set_event_destination
|
||||||
|
- [X] delete_contact
|
||||||
|
- [X] delete_contact_list
|
||||||
|
- [ ] delete_custom_verification_email_template
|
||||||
|
- [ ] delete_dedicated_ip_pool
|
||||||
|
- [ ] delete_email_identity
|
||||||
|
- [ ] delete_email_identity_policy
|
||||||
|
- [ ] delete_email_template
|
||||||
|
- [ ] delete_suppressed_destination
|
||||||
|
- [ ] get_account
|
||||||
|
- [ ] get_blacklist_reports
|
||||||
|
- [ ] get_configuration_set
|
||||||
|
- [ ] get_configuration_set_event_destinations
|
||||||
|
- [X] get_contact
|
||||||
|
- [X] get_contact_list
|
||||||
|
- [ ] get_custom_verification_email_template
|
||||||
|
- [ ] get_dedicated_ip
|
||||||
|
- [ ] get_dedicated_ip_pool
|
||||||
|
- [ ] get_dedicated_ips
|
||||||
|
- [ ] get_deliverability_dashboard_options
|
||||||
|
- [ ] get_deliverability_test_report
|
||||||
|
- [ ] get_domain_deliverability_campaign
|
||||||
|
- [ ] get_domain_statistics_report
|
||||||
|
- [ ] get_email_identity
|
||||||
|
- [ ] get_email_identity_policies
|
||||||
|
- [ ] get_email_template
|
||||||
|
- [ ] get_import_job
|
||||||
|
- [ ] get_suppressed_destination
|
||||||
|
- [ ] list_configuration_sets
|
||||||
|
- [X] list_contact_lists
|
||||||
|
- [X] list_contacts
|
||||||
|
- [ ] list_custom_verification_email_templates
|
||||||
|
- [ ] list_dedicated_ip_pools
|
||||||
|
- [ ] list_deliverability_test_reports
|
||||||
|
- [ ] list_domain_deliverability_campaigns
|
||||||
|
- [ ] list_email_identities
|
||||||
|
- [ ] list_email_templates
|
||||||
|
- [ ] list_import_jobs
|
||||||
|
- [ ] list_recommendations
|
||||||
|
- [ ] list_suppressed_destinations
|
||||||
|
- [ ] list_tags_for_resource
|
||||||
|
- [ ] put_account_dedicated_ip_warmup_attributes
|
||||||
|
- [ ] put_account_details
|
||||||
|
- [ ] put_account_sending_attributes
|
||||||
|
- [ ] put_account_suppression_attributes
|
||||||
|
- [ ] put_account_vdm_attributes
|
||||||
|
- [ ] put_configuration_set_delivery_options
|
||||||
|
- [ ] put_configuration_set_reputation_options
|
||||||
|
- [ ] put_configuration_set_sending_options
|
||||||
|
- [ ] put_configuration_set_suppression_options
|
||||||
|
- [ ] put_configuration_set_tracking_options
|
||||||
|
- [ ] put_configuration_set_vdm_options
|
||||||
|
- [ ] put_dedicated_ip_in_pool
|
||||||
|
- [ ] put_dedicated_ip_warmup_attributes
|
||||||
|
- [ ] put_deliverability_dashboard_option
|
||||||
|
- [ ] put_email_identity_configuration_set_attributes
|
||||||
|
- [ ] put_email_identity_dkim_attributes
|
||||||
|
- [ ] put_email_identity_dkim_signing_attributes
|
||||||
|
- [ ] put_email_identity_feedback_attributes
|
||||||
|
- [ ] put_email_identity_mail_from_attributes
|
||||||
|
- [ ] put_suppressed_destination
|
||||||
|
- [ ] send_bulk_email
|
||||||
|
- [ ] send_custom_verification_email
|
||||||
|
- [X] send_email
|
||||||
|
- [ ] tag_resource
|
||||||
|
- [ ] test_render_email_template
|
||||||
|
- [ ] untag_resource
|
||||||
|
- [ ] update_configuration_set_event_destination
|
||||||
|
- [ ] update_contact
|
||||||
|
- [ ] update_contact_list
|
||||||
|
- [ ] update_custom_verification_email_template
|
||||||
|
- [ ] update_email_identity_policy
|
||||||
|
- [ ] update_email_template
|
||||||
|
</details>
|
||||||
|
|
||||||
## signer
|
## signer
|
||||||
<details>
|
<details>
|
||||||
<summary>23% implemented</summary>
|
<summary>23% implemented</summary>
|
||||||
@ -7113,6 +7230,7 @@
|
|||||||
- omics
|
- omics
|
||||||
- opensearchserverless
|
- opensearchserverless
|
||||||
- opsworkscm
|
- opsworkscm
|
||||||
|
- osis
|
||||||
- outposts
|
- outposts
|
||||||
- panorama
|
- panorama
|
||||||
- personalize-events
|
- personalize-events
|
||||||
@ -7152,7 +7270,6 @@
|
|||||||
- serverlessrepo
|
- serverlessrepo
|
||||||
- servicecatalog
|
- servicecatalog
|
||||||
- servicecatalog-appregistry
|
- servicecatalog-appregistry
|
||||||
- sesv2
|
|
||||||
- shield
|
- shield
|
||||||
- simspaceweaver
|
- simspaceweaver
|
||||||
- sms
|
- sms
|
||||||
|
@ -28,6 +28,8 @@ athena
|
|||||||
- [ ] batch_get_named_query
|
- [ ] batch_get_named_query
|
||||||
- [ ] batch_get_prepared_statement
|
- [ ] batch_get_prepared_statement
|
||||||
- [ ] batch_get_query_execution
|
- [ ] batch_get_query_execution
|
||||||
|
- [ ] cancel_capacity_reservation
|
||||||
|
- [ ] create_capacity_reservation
|
||||||
- [X] create_data_catalog
|
- [X] create_data_catalog
|
||||||
- [X] create_named_query
|
- [X] create_named_query
|
||||||
- [ ] create_notebook
|
- [ ] create_notebook
|
||||||
@ -43,6 +45,8 @@ athena
|
|||||||
- [ ] get_calculation_execution
|
- [ ] get_calculation_execution
|
||||||
- [ ] get_calculation_execution_code
|
- [ ] get_calculation_execution_code
|
||||||
- [ ] get_calculation_execution_status
|
- [ ] get_calculation_execution_status
|
||||||
|
- [ ] get_capacity_assignment_configuration
|
||||||
|
- [ ] get_capacity_reservation
|
||||||
- [X] get_data_catalog
|
- [X] get_data_catalog
|
||||||
- [ ] get_database
|
- [ ] get_database
|
||||||
- [X] get_named_query
|
- [X] get_named_query
|
||||||
@ -104,6 +108,7 @@ athena
|
|||||||
- [ ] import_notebook
|
- [ ] import_notebook
|
||||||
- [ ] list_application_dpu_sizes
|
- [ ] list_application_dpu_sizes
|
||||||
- [ ] list_calculation_executions
|
- [ ] list_calculation_executions
|
||||||
|
- [ ] list_capacity_reservations
|
||||||
- [X] list_data_catalogs
|
- [X] list_data_catalogs
|
||||||
- [ ] list_databases
|
- [ ] list_databases
|
||||||
- [ ] list_engine_versions
|
- [ ] list_engine_versions
|
||||||
@ -117,6 +122,7 @@ athena
|
|||||||
- [ ] list_table_metadata
|
- [ ] list_table_metadata
|
||||||
- [ ] list_tags_for_resource
|
- [ ] list_tags_for_resource
|
||||||
- [X] list_work_groups
|
- [X] list_work_groups
|
||||||
|
- [ ] put_capacity_assignment_configuration
|
||||||
- [ ] start_calculation_execution
|
- [ ] start_calculation_execution
|
||||||
- [X] start_query_execution
|
- [X] start_query_execution
|
||||||
- [ ] start_session
|
- [ ] start_session
|
||||||
@ -125,6 +131,7 @@ athena
|
|||||||
- [ ] tag_resource
|
- [ ] tag_resource
|
||||||
- [ ] terminate_session
|
- [ ] terminate_session
|
||||||
- [ ] untag_resource
|
- [ ] untag_resource
|
||||||
|
- [ ] update_capacity_reservation
|
||||||
- [ ] update_data_catalog
|
- [ ] update_data_catalog
|
||||||
- [ ] update_named_query
|
- [ ] update_named_query
|
||||||
- [ ] update_notebook
|
- [ ] update_notebook
|
||||||
|
@ -25,6 +25,7 @@ datasync
|
|||||||
|
|
||||||
|start-h3| Implemented features for this service |end-h3|
|
|start-h3| Implemented features for this service |end-h3|
|
||||||
|
|
||||||
|
- [ ] add_storage_system
|
||||||
- [X] cancel_task_execution
|
- [X] cancel_task_execution
|
||||||
- [ ] create_agent
|
- [ ] create_agent
|
||||||
- [ ] create_location_efs
|
- [ ] create_location_efs
|
||||||
@ -42,6 +43,7 @@ datasync
|
|||||||
- [X] delete_location
|
- [X] delete_location
|
||||||
- [X] delete_task
|
- [X] delete_task
|
||||||
- [ ] describe_agent
|
- [ ] describe_agent
|
||||||
|
- [ ] describe_discovery_job
|
||||||
- [ ] describe_location_efs
|
- [ ] describe_location_efs
|
||||||
- [ ] describe_location_fsx_lustre
|
- [ ] describe_location_fsx_lustre
|
||||||
- [ ] describe_location_fsx_ontap
|
- [ ] describe_location_fsx_ontap
|
||||||
@ -52,21 +54,32 @@ datasync
|
|||||||
- [ ] describe_location_object_storage
|
- [ ] describe_location_object_storage
|
||||||
- [ ] describe_location_s3
|
- [ ] describe_location_s3
|
||||||
- [ ] describe_location_smb
|
- [ ] describe_location_smb
|
||||||
|
- [ ] describe_storage_system
|
||||||
|
- [ ] describe_storage_system_resource_metrics
|
||||||
|
- [ ] describe_storage_system_resources
|
||||||
- [ ] describe_task
|
- [ ] describe_task
|
||||||
- [ ] describe_task_execution
|
- [ ] describe_task_execution
|
||||||
|
- [ ] generate_recommendations
|
||||||
- [ ] list_agents
|
- [ ] list_agents
|
||||||
|
- [ ] list_discovery_jobs
|
||||||
- [ ] list_locations
|
- [ ] list_locations
|
||||||
|
- [ ] list_storage_systems
|
||||||
- [ ] list_tags_for_resource
|
- [ ] list_tags_for_resource
|
||||||
- [ ] list_task_executions
|
- [ ] list_task_executions
|
||||||
- [ ] list_tasks
|
- [ ] list_tasks
|
||||||
|
- [ ] remove_storage_system
|
||||||
|
- [ ] start_discovery_job
|
||||||
- [X] start_task_execution
|
- [X] start_task_execution
|
||||||
|
- [ ] stop_discovery_job
|
||||||
- [ ] tag_resource
|
- [ ] tag_resource
|
||||||
- [ ] untag_resource
|
- [ ] untag_resource
|
||||||
- [ ] update_agent
|
- [ ] update_agent
|
||||||
|
- [ ] update_discovery_job
|
||||||
- [ ] update_location_hdfs
|
- [ ] update_location_hdfs
|
||||||
- [ ] update_location_nfs
|
- [ ] update_location_nfs
|
||||||
- [ ] update_location_object_storage
|
- [ ] update_location_object_storage
|
||||||
- [ ] update_location_smb
|
- [ ] update_location_smb
|
||||||
|
- [ ] update_storage_system
|
||||||
- [X] update_task
|
- [X] update_task
|
||||||
- [ ] update_task_execution
|
- [ ] update_task_execution
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ emr-containers
|
|||||||
- [ ] describe_job_template
|
- [ ] describe_job_template
|
||||||
- [ ] describe_managed_endpoint
|
- [ ] describe_managed_endpoint
|
||||||
- [X] describe_virtual_cluster
|
- [X] describe_virtual_cluster
|
||||||
|
- [ ] get_managed_endpoint_session_credentials
|
||||||
- [X] list_job_runs
|
- [X] list_job_runs
|
||||||
- [ ] list_job_templates
|
- [ ] list_job_templates
|
||||||
- [ ] list_managed_endpoints
|
- [ ] list_managed_endpoints
|
||||||
|
@ -37,7 +37,7 @@ glue
|
|||||||
- [ ] batch_get_dev_endpoints
|
- [ ] batch_get_dev_endpoints
|
||||||
- [X] batch_get_jobs
|
- [X] batch_get_jobs
|
||||||
- [X] batch_get_partition
|
- [X] batch_get_partition
|
||||||
- [ ] batch_get_triggers
|
- [X] batch_get_triggers
|
||||||
- [ ] batch_get_workflows
|
- [ ] batch_get_workflows
|
||||||
- [ ] batch_stop_job_run
|
- [ ] batch_stop_job_run
|
||||||
- [X] batch_update_partition
|
- [X] batch_update_partition
|
||||||
@ -68,7 +68,7 @@ glue
|
|||||||
- [ ] create_security_configuration
|
- [ ] create_security_configuration
|
||||||
- [ ] create_session
|
- [ ] create_session
|
||||||
- [X] create_table
|
- [X] create_table
|
||||||
- [ ] create_trigger
|
- [X] create_trigger
|
||||||
- [ ] create_user_defined_function
|
- [ ] create_user_defined_function
|
||||||
- [ ] create_workflow
|
- [ ] create_workflow
|
||||||
- [ ] delete_blueprint
|
- [ ] delete_blueprint
|
||||||
@ -93,7 +93,7 @@ glue
|
|||||||
- [ ] delete_session
|
- [ ] delete_session
|
||||||
- [X] delete_table
|
- [X] delete_table
|
||||||
- [X] delete_table_version
|
- [X] delete_table_version
|
||||||
- [ ] delete_trigger
|
- [X] delete_trigger
|
||||||
- [ ] delete_user_defined_function
|
- [ ] delete_user_defined_function
|
||||||
- [ ] delete_workflow
|
- [ ] delete_workflow
|
||||||
- [ ] get_blueprint
|
- [ ] get_blueprint
|
||||||
@ -162,8 +162,8 @@ glue
|
|||||||
- [X] get_table_versions
|
- [X] get_table_versions
|
||||||
- [X] get_tables
|
- [X] get_tables
|
||||||
- [X] get_tags
|
- [X] get_tags
|
||||||
- [ ] get_trigger
|
- [X] get_trigger
|
||||||
- [ ] get_triggers
|
- [X] get_triggers
|
||||||
- [ ] get_unfiltered_partition_metadata
|
- [ ] get_unfiltered_partition_metadata
|
||||||
- [ ] get_unfiltered_partitions_metadata
|
- [ ] get_unfiltered_partitions_metadata
|
||||||
- [ ] get_unfiltered_table_metadata
|
- [ ] get_unfiltered_table_metadata
|
||||||
@ -190,7 +190,7 @@ glue
|
|||||||
- [ ] list_schemas
|
- [ ] list_schemas
|
||||||
- [ ] list_sessions
|
- [ ] list_sessions
|
||||||
- [ ] list_statements
|
- [ ] list_statements
|
||||||
- [ ] list_triggers
|
- [X] list_triggers
|
||||||
- [ ] list_workflows
|
- [ ] list_workflows
|
||||||
- [ ] put_data_catalog_encryption_settings
|
- [ ] put_data_catalog_encryption_settings
|
||||||
- [ ] put_resource_policy
|
- [ ] put_resource_policy
|
||||||
@ -213,12 +213,12 @@ glue
|
|||||||
- [X] start_job_run
|
- [X] start_job_run
|
||||||
- [ ] start_ml_evaluation_task_run
|
- [ ] start_ml_evaluation_task_run
|
||||||
- [ ] start_ml_labeling_set_generation_task_run
|
- [ ] start_ml_labeling_set_generation_task_run
|
||||||
- [ ] start_trigger
|
- [X] start_trigger
|
||||||
- [ ] start_workflow_run
|
- [ ] start_workflow_run
|
||||||
- [X] stop_crawler
|
- [X] stop_crawler
|
||||||
- [ ] stop_crawler_schedule
|
- [ ] stop_crawler_schedule
|
||||||
- [ ] stop_session
|
- [ ] stop_session
|
||||||
- [ ] stop_trigger
|
- [X] stop_trigger
|
||||||
- [ ] stop_workflow_run
|
- [ ] stop_workflow_run
|
||||||
- [X] tag_resource
|
- [X] tag_resource
|
||||||
- [X] untag_resource
|
- [X] untag_resource
|
||||||
|
@ -86,6 +86,7 @@ guardduty
|
|||||||
- [ ] list_publishing_destinations
|
- [ ] list_publishing_destinations
|
||||||
- [ ] list_tags_for_resource
|
- [ ] list_tags_for_resource
|
||||||
- [ ] list_threat_intel_sets
|
- [ ] list_threat_intel_sets
|
||||||
|
- [ ] start_malware_scan
|
||||||
- [ ] start_monitoring_members
|
- [ ] start_monitoring_members
|
||||||
- [ ] stop_monitoring_members
|
- [ ] stop_monitoring_members
|
||||||
- [ ] tag_resource
|
- [ ] tag_resource
|
||||||
|
@ -98,6 +98,9 @@ pinpoint
|
|||||||
- [ ] get_journey_date_range_kpi
|
- [ ] get_journey_date_range_kpi
|
||||||
- [ ] get_journey_execution_activity_metrics
|
- [ ] get_journey_execution_activity_metrics
|
||||||
- [ ] get_journey_execution_metrics
|
- [ ] get_journey_execution_metrics
|
||||||
|
- [ ] get_journey_run_execution_activity_metrics
|
||||||
|
- [ ] get_journey_run_execution_metrics
|
||||||
|
- [ ] get_journey_runs
|
||||||
- [ ] get_push_template
|
- [ ] get_push_template
|
||||||
- [ ] get_recommender_configuration
|
- [ ] get_recommender_configuration
|
||||||
- [ ] get_recommender_configurations
|
- [ ] get_recommender_configurations
|
||||||
|
116
docs/docs/services/sesv2.rst
Normal file
116
docs/docs/services/sesv2.rst
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
.. _implementedservice_sesv2:
|
||||||
|
|
||||||
|
.. |start-h3| raw:: html
|
||||||
|
|
||||||
|
<h3>
|
||||||
|
|
||||||
|
.. |end-h3| raw:: html
|
||||||
|
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
=====
|
||||||
|
sesv2
|
||||||
|
=====
|
||||||
|
|
||||||
|
.. autoclass:: moto.sesv2.models.SESV2Backend
|
||||||
|
|
||||||
|
|start-h3| Example usage |end-h3|
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_sesv2_behaviour:
|
||||||
|
boto3.client("sesv2")
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|start-h3| Implemented features for this service |end-h3|
|
||||||
|
|
||||||
|
- [ ] batch_get_metric_data
|
||||||
|
- [ ] create_configuration_set
|
||||||
|
- [ ] create_configuration_set_event_destination
|
||||||
|
- [X] create_contact
|
||||||
|
- [X] create_contact_list
|
||||||
|
- [ ] create_custom_verification_email_template
|
||||||
|
- [ ] create_dedicated_ip_pool
|
||||||
|
- [ ] create_deliverability_test_report
|
||||||
|
- [ ] create_email_identity
|
||||||
|
- [ ] create_email_identity_policy
|
||||||
|
- [ ] create_email_template
|
||||||
|
- [ ] create_import_job
|
||||||
|
- [ ] delete_configuration_set
|
||||||
|
- [ ] delete_configuration_set_event_destination
|
||||||
|
- [X] delete_contact
|
||||||
|
- [X] delete_contact_list
|
||||||
|
- [ ] delete_custom_verification_email_template
|
||||||
|
- [ ] delete_dedicated_ip_pool
|
||||||
|
- [ ] delete_email_identity
|
||||||
|
- [ ] delete_email_identity_policy
|
||||||
|
- [ ] delete_email_template
|
||||||
|
- [ ] delete_suppressed_destination
|
||||||
|
- [ ] get_account
|
||||||
|
- [ ] get_blacklist_reports
|
||||||
|
- [ ] get_configuration_set
|
||||||
|
- [ ] get_configuration_set_event_destinations
|
||||||
|
- [X] get_contact
|
||||||
|
- [X] get_contact_list
|
||||||
|
- [ ] get_custom_verification_email_template
|
||||||
|
- [ ] get_dedicated_ip
|
||||||
|
- [ ] get_dedicated_ip_pool
|
||||||
|
- [ ] get_dedicated_ips
|
||||||
|
- [ ] get_deliverability_dashboard_options
|
||||||
|
- [ ] get_deliverability_test_report
|
||||||
|
- [ ] get_domain_deliverability_campaign
|
||||||
|
- [ ] get_domain_statistics_report
|
||||||
|
- [ ] get_email_identity
|
||||||
|
- [ ] get_email_identity_policies
|
||||||
|
- [ ] get_email_template
|
||||||
|
- [ ] get_import_job
|
||||||
|
- [ ] get_suppressed_destination
|
||||||
|
- [ ] list_configuration_sets
|
||||||
|
- [X] list_contact_lists
|
||||||
|
- [X] list_contacts
|
||||||
|
- [ ] list_custom_verification_email_templates
|
||||||
|
- [ ] list_dedicated_ip_pools
|
||||||
|
- [ ] list_deliverability_test_reports
|
||||||
|
- [ ] list_domain_deliverability_campaigns
|
||||||
|
- [ ] list_email_identities
|
||||||
|
- [ ] list_email_templates
|
||||||
|
- [ ] list_import_jobs
|
||||||
|
- [ ] list_recommendations
|
||||||
|
- [ ] list_suppressed_destinations
|
||||||
|
- [ ] list_tags_for_resource
|
||||||
|
- [ ] put_account_dedicated_ip_warmup_attributes
|
||||||
|
- [ ] put_account_details
|
||||||
|
- [ ] put_account_sending_attributes
|
||||||
|
- [ ] put_account_suppression_attributes
|
||||||
|
- [ ] put_account_vdm_attributes
|
||||||
|
- [ ] put_configuration_set_delivery_options
|
||||||
|
- [ ] put_configuration_set_reputation_options
|
||||||
|
- [ ] put_configuration_set_sending_options
|
||||||
|
- [ ] put_configuration_set_suppression_options
|
||||||
|
- [ ] put_configuration_set_tracking_options
|
||||||
|
- [ ] put_configuration_set_vdm_options
|
||||||
|
- [ ] put_dedicated_ip_in_pool
|
||||||
|
- [ ] put_dedicated_ip_warmup_attributes
|
||||||
|
- [ ] put_deliverability_dashboard_option
|
||||||
|
- [ ] put_email_identity_configuration_set_attributes
|
||||||
|
- [ ] put_email_identity_dkim_attributes
|
||||||
|
- [ ] put_email_identity_dkim_signing_attributes
|
||||||
|
- [ ] put_email_identity_feedback_attributes
|
||||||
|
- [ ] put_email_identity_mail_from_attributes
|
||||||
|
- [ ] put_suppressed_destination
|
||||||
|
- [ ] send_bulk_email
|
||||||
|
- [ ] send_custom_verification_email
|
||||||
|
- [X] send_email
|
||||||
|
- [ ] tag_resource
|
||||||
|
- [ ] test_render_email_template
|
||||||
|
- [ ] untag_resource
|
||||||
|
- [ ] update_configuration_set_event_destination
|
||||||
|
- [ ] update_contact
|
||||||
|
- [ ] update_contact_list
|
||||||
|
- [ ] update_custom_verification_email_template
|
||||||
|
- [ ] update_email_identity_policy
|
||||||
|
- [ ] update_email_template
|
||||||
|
|
@ -109,10 +109,6 @@ ssm
|
|||||||
- [ ] get_automation_execution
|
- [ ] get_automation_execution
|
||||||
- [ ] get_calendar_state
|
- [ ] get_calendar_state
|
||||||
- [X] get_command_invocation
|
- [X] get_command_invocation
|
||||||
|
|
||||||
https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_GetCommandInvocation.html
|
|
||||||
|
|
||||||
|
|
||||||
- [ ] get_connection_status
|
- [ ] get_connection_status
|
||||||
- [ ] get_default_patch_baseline
|
- [ ] get_default_patch_baseline
|
||||||
- [ ] get_deployable_patch_snapshot_for_instance
|
- [ ] get_deployable_patch_snapshot_for_instance
|
||||||
@ -148,7 +144,7 @@ ssm
|
|||||||
- [ ] list_command_invocations
|
- [ ] list_command_invocations
|
||||||
- [X] list_commands
|
- [X] list_commands
|
||||||
|
|
||||||
https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_ListCommands.html
|
Pagination and the Filters-parameter is not yet implemented
|
||||||
|
|
||||||
|
|
||||||
- [ ] list_compliance_items
|
- [ ] list_compliance_items
|
||||||
|
@ -150,6 +150,7 @@ mock_servicequotas = lazy_load(
|
|||||||
".servicequotas", "mock_servicequotas", boto3_name="service-quotas"
|
".servicequotas", "mock_servicequotas", boto3_name="service-quotas"
|
||||||
)
|
)
|
||||||
mock_ses = lazy_load(".ses", "mock_ses")
|
mock_ses = lazy_load(".ses", "mock_ses")
|
||||||
|
mock_sesv2 = lazy_load(".sesv2", "mock_sesv2")
|
||||||
mock_servicediscovery = lazy_load(".servicediscovery", "mock_servicediscovery")
|
mock_servicediscovery = lazy_load(".servicediscovery", "mock_servicediscovery")
|
||||||
mock_signer = lazy_load(".signer", "mock_signer")
|
mock_signer = lazy_load(".signer", "mock_signer")
|
||||||
mock_sns = lazy_load(".sns", "mock_sns")
|
mock_sns = lazy_load(".sns", "mock_sns")
|
||||||
|
@ -158,6 +158,8 @@ backend_url_patterns = [
|
|||||||
("service-quotas", re.compile("https?://servicequotas\\.(.+)\\.amazonaws\\.com")),
|
("service-quotas", re.compile("https?://servicequotas\\.(.+)\\.amazonaws\\.com")),
|
||||||
("ses", re.compile("https?://email\\.(.+)\\.amazonaws\\.com")),
|
("ses", re.compile("https?://email\\.(.+)\\.amazonaws\\.com")),
|
||||||
("ses", re.compile("https?://ses\\.(.+)\\.amazonaws\\.com")),
|
("ses", re.compile("https?://ses\\.(.+)\\.amazonaws\\.com")),
|
||||||
|
("sesv2", re.compile("https?://ses\\.(.+)\\.amazonaws\\.com")),
|
||||||
|
("sesv2", re.compile("https?://email\\.(.+)\\.amazonaws\\.com")),
|
||||||
("signer", re.compile("https?://signer\\.(.+)\\.amazonaws\\.com")),
|
("signer", re.compile("https?://signer\\.(.+)\\.amazonaws\\.com")),
|
||||||
("sns", re.compile("https?://sns\\.(.+)\\.amazonaws\\.com")),
|
("sns", re.compile("https?://sns\\.(.+)\\.amazonaws\\.com")),
|
||||||
("sqs", re.compile("https?://(.*\\.)?(queue|sqs)\\.(.*\\.)?amazonaws\\.com")),
|
("sqs", re.compile("https?://(.*\\.)?(queue|sqs)\\.(.*\\.)?amazonaws\\.com")),
|
||||||
|
@ -153,6 +153,8 @@ class DomainDispatcherApplication:
|
|||||||
path.startswith("/v20180820/") or "s3-control" in environ["HTTP_HOST"]
|
path.startswith("/v20180820/") or "s3-control" in environ["HTTP_HOST"]
|
||||||
):
|
):
|
||||||
host = "s3control"
|
host = "s3control"
|
||||||
|
elif service == "ses" and path.startswith("/v2/"):
|
||||||
|
host = "sesv2"
|
||||||
else:
|
else:
|
||||||
host = f"{service}.{region}.amazonaws.com"
|
host = f"{service}.{region}.amazonaws.com"
|
||||||
|
|
||||||
|
5
moto/sesv2/__init__.py
Normal file
5
moto/sesv2/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
"""sesv2 module initialization; sets value for base decorator."""
|
||||||
|
from .models import sesv2_backends
|
||||||
|
from ..core.models import base_decorator
|
||||||
|
|
||||||
|
mock_sesv2 = base_decorator(sesv2_backends)
|
8
moto/sesv2/exceptions.py
Normal file
8
moto/sesv2/exceptions.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from moto.core.exceptions import JsonRESTError
|
||||||
|
|
||||||
|
|
||||||
|
class NotFoundException(JsonRESTError):
|
||||||
|
code = 404
|
||||||
|
|
||||||
|
def __init__(self, message: str):
|
||||||
|
super().__init__("NotFoundException", message)
|
166
moto/sesv2/models.py
Normal file
166
moto/sesv2/models.py
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
"""SESV2Backend class with methods for supported APIs."""
|
||||||
|
|
||||||
|
from datetime import datetime as dt
|
||||||
|
from moto.core import BackendDict, BaseBackend, BaseModel
|
||||||
|
from ..ses.models import ses_backends, Message, RawMessage
|
||||||
|
from typing import Dict, List, Any
|
||||||
|
from .exceptions import NotFoundException
|
||||||
|
from moto.core.utils import iso_8601_datetime_with_milliseconds
|
||||||
|
|
||||||
|
|
||||||
|
class Contact(BaseModel):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
contact_list_name: str,
|
||||||
|
email_address: str,
|
||||||
|
topic_preferences: List[Dict[str, str]],
|
||||||
|
unsubscribe_all: bool,
|
||||||
|
) -> None:
|
||||||
|
self.contact_list_name = contact_list_name
|
||||||
|
self.email_address = email_address
|
||||||
|
self.topic_default_preferences: List[Dict[str, str]] = []
|
||||||
|
self.topic_preferences = topic_preferences
|
||||||
|
self.unsubscribe_all = unsubscribe_all
|
||||||
|
self.created_timestamp = iso_8601_datetime_with_milliseconds(dt.utcnow())
|
||||||
|
self.last_updated_timestamp = iso_8601_datetime_with_milliseconds(dt.utcnow())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def response_object(self) -> Dict[str, Any]: # type: ignore[misc]
|
||||||
|
return {
|
||||||
|
"ContactListName": self.contact_list_name,
|
||||||
|
"EmailAddress": self.email_address,
|
||||||
|
"TopicDefaultPreferences": self.topic_default_preferences,
|
||||||
|
"TopicPreferences": self.topic_preferences,
|
||||||
|
"UnsubscribeAll": self.unsubscribe_all,
|
||||||
|
"CreatedTimestamp": self.created_timestamp,
|
||||||
|
"LastUpdatedTimestamp": self.last_updated_timestamp,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ContactList(BaseModel):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
contact_list_name: str,
|
||||||
|
description: str,
|
||||||
|
topics: List[Dict[str, str]],
|
||||||
|
) -> None:
|
||||||
|
self.contact_list_name = contact_list_name
|
||||||
|
self.description = description
|
||||||
|
self.topics = topics
|
||||||
|
self.created_timestamp = iso_8601_datetime_with_milliseconds(dt.utcnow())
|
||||||
|
self.last_updated_timestamp = iso_8601_datetime_with_milliseconds(dt.utcnow())
|
||||||
|
self.contacts: Dict[str, Contact] = {}
|
||||||
|
|
||||||
|
def create_contact(self, contact_list_name: str, params: Dict[str, Any]) -> None:
|
||||||
|
email_address = params["EmailAddress"]
|
||||||
|
topic_preferences = (
|
||||||
|
[] if "TopicPreferences" not in params else params["TopicPreferences"]
|
||||||
|
)
|
||||||
|
unsubscribe_all = (
|
||||||
|
False if "UnsubscribeAll" not in params else params["UnsubscribeAll"]
|
||||||
|
)
|
||||||
|
new_contact = Contact(
|
||||||
|
contact_list_name, email_address, topic_preferences, unsubscribe_all
|
||||||
|
)
|
||||||
|
self.contacts[email_address] = new_contact
|
||||||
|
|
||||||
|
def list_contacts(self) -> List[Contact]:
|
||||||
|
return self.contacts.values() # type: ignore[return-value]
|
||||||
|
|
||||||
|
def get_contact(self, email: str) -> Contact:
|
||||||
|
if email in self.contacts:
|
||||||
|
return self.contacts[email]
|
||||||
|
else:
|
||||||
|
raise NotFoundException(f"{email} doesn't exist in List.")
|
||||||
|
|
||||||
|
def delete_contact(self, email: str) -> None:
|
||||||
|
# delete if contact exists, otherwise get_contact will throw appropriate exception
|
||||||
|
if self.get_contact(email):
|
||||||
|
del self.contacts[email]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def response_object(self) -> Dict[str, Any]: # type: ignore[misc]
|
||||||
|
return {
|
||||||
|
"ContactListName": self.contact_list_name,
|
||||||
|
"Description": self.description,
|
||||||
|
"Topics": self.topics,
|
||||||
|
"CreatedTimestamp": self.created_timestamp,
|
||||||
|
"LastUpdatedTimestamp": self.last_updated_timestamp,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class SESV2Backend(BaseBackend):
|
||||||
|
"""Implementation of SESV2 APIs, piggy back on v1 SES"""
|
||||||
|
|
||||||
|
def __init__(self, region_name: str, account_id: str):
|
||||||
|
super().__init__(region_name, account_id)
|
||||||
|
self.contacts: Dict[str, Contact] = {}
|
||||||
|
self.contacts_lists: Dict[str, ContactList] = {}
|
||||||
|
|
||||||
|
def create_contact_list(self, params: Dict[str, Any]) -> None:
|
||||||
|
name = params["ContactListName"]
|
||||||
|
description = params.get("Description")
|
||||||
|
topics = [] if "Topics" not in params else params["Topics"]
|
||||||
|
new_list = ContactList(name, str(description), topics)
|
||||||
|
self.contacts_lists[name] = new_list
|
||||||
|
|
||||||
|
def get_contact_list(self, contact_list_name: str) -> ContactList:
|
||||||
|
if contact_list_name in self.contacts_lists:
|
||||||
|
return self.contacts_lists[contact_list_name]
|
||||||
|
else:
|
||||||
|
raise NotFoundException(
|
||||||
|
f"List with name: {contact_list_name} doesn't exist."
|
||||||
|
)
|
||||||
|
|
||||||
|
def list_contact_lists(self) -> List[ContactList]:
|
||||||
|
return self.contacts_lists.values() # type: ignore[return-value]
|
||||||
|
|
||||||
|
def delete_contact_list(self, name: str) -> None:
|
||||||
|
if name in self.contacts_lists:
|
||||||
|
del self.contacts_lists[name]
|
||||||
|
else:
|
||||||
|
raise NotFoundException(f"List with name: {name} doesn't exist")
|
||||||
|
|
||||||
|
def create_contact(self, contact_list_name: str, params: Dict[str, Any]) -> None:
|
||||||
|
contact_list = self.get_contact_list(contact_list_name)
|
||||||
|
contact_list.create_contact(contact_list_name, params)
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_contact(self, email: str, contact_list_name: str) -> Contact:
|
||||||
|
contact_list = self.get_contact_list(contact_list_name)
|
||||||
|
contact = contact_list.get_contact(email)
|
||||||
|
return contact
|
||||||
|
|
||||||
|
def list_contacts(self, contact_list_name: str) -> List[Contact]:
|
||||||
|
contact_list = self.get_contact_list(contact_list_name)
|
||||||
|
contacts = contact_list.list_contacts()
|
||||||
|
return contacts
|
||||||
|
|
||||||
|
def delete_contact(self, email: str, contact_list_name: str) -> None:
|
||||||
|
contact_list = self.get_contact_list(contact_list_name)
|
||||||
|
contact_list.delete_contact(email)
|
||||||
|
return
|
||||||
|
|
||||||
|
def send_email(
|
||||||
|
self, source: str, destinations: Dict[str, List[str]], subject: str, body: str
|
||||||
|
) -> Message:
|
||||||
|
v1_backend = ses_backends[self.account_id][self.region_name]
|
||||||
|
message = v1_backend.send_email(
|
||||||
|
source=source,
|
||||||
|
destinations=destinations,
|
||||||
|
subject=subject,
|
||||||
|
body=body,
|
||||||
|
)
|
||||||
|
return message
|
||||||
|
|
||||||
|
def send_raw_email(
|
||||||
|
self, source: str, destinations: List[str], raw_data: str
|
||||||
|
) -> RawMessage:
|
||||||
|
v1_backend = ses_backends[self.account_id][self.region_name]
|
||||||
|
message = v1_backend.send_raw_email(
|
||||||
|
source=source, destinations=destinations, raw_data=raw_data
|
||||||
|
)
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
sesv2_backends = BackendDict(SESV2Backend, "sesv2")
|
102
moto/sesv2/responses.py
Normal file
102
moto/sesv2/responses.py
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
"""Handles incoming sesv2 requests, invokes methods, returns responses."""
|
||||||
|
import json
|
||||||
|
|
||||||
|
from moto.core.responses import BaseResponse
|
||||||
|
from .models import sesv2_backends
|
||||||
|
from ..ses.responses import SEND_EMAIL_RESPONSE
|
||||||
|
from .models import SESV2Backend
|
||||||
|
from typing import List, Dict, Any
|
||||||
|
from urllib.parse import unquote
|
||||||
|
|
||||||
|
|
||||||
|
class SESV2Response(BaseResponse):
|
||||||
|
"""Handler for SESV2 requests and responses."""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__(service_name="sesv2")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sesv2_backend(self) -> SESV2Backend:
|
||||||
|
"""Return backend instance specific for this region."""
|
||||||
|
return sesv2_backends[self.current_account][self.region]
|
||||||
|
|
||||||
|
def send_email(self) -> str:
|
||||||
|
"""Piggy back on functionality from v1 mostly"""
|
||||||
|
|
||||||
|
params = get_params_dict(self.querystring)
|
||||||
|
from_email_address = params.get("FromEmailAddress")
|
||||||
|
destination = params.get("Destination")
|
||||||
|
content = params.get("Content")
|
||||||
|
if "Raw" in content:
|
||||||
|
all_destinations: List[str] = []
|
||||||
|
if "ToAddresses" in destination:
|
||||||
|
all_destinations = all_destinations + destination["ToAddresses"]
|
||||||
|
if "CcAddresses" in destination:
|
||||||
|
all_destinations = all_destinations + destination["CcAddresses"]
|
||||||
|
if "BccAddresses" in destination:
|
||||||
|
all_destinations = all_destinations + destination["BccAddresses"]
|
||||||
|
message = self.sesv2_backend.send_raw_email(
|
||||||
|
source=from_email_address,
|
||||||
|
destinations=all_destinations,
|
||||||
|
raw_data=content["Raw"]["Data"],
|
||||||
|
)
|
||||||
|
elif "Simple" in content:
|
||||||
|
message = self.sesv2_backend.send_email( # type: ignore
|
||||||
|
source=from_email_address,
|
||||||
|
destinations=destination,
|
||||||
|
subject=content["Simple"]["Subject"]["Data"],
|
||||||
|
body=content["Simple"]["Subject"]["Data"],
|
||||||
|
)
|
||||||
|
elif "Template" in content:
|
||||||
|
raise NotImplementedError("Template functionality not ready")
|
||||||
|
|
||||||
|
# use v1 templates as response same in v1 and v2
|
||||||
|
template = self.response_template(SEND_EMAIL_RESPONSE)
|
||||||
|
return template.render(message=message)
|
||||||
|
|
||||||
|
def create_contact_list(self) -> str:
|
||||||
|
params = get_params_dict(self.data)
|
||||||
|
self.sesv2_backend.create_contact_list(params)
|
||||||
|
return json.dumps({})
|
||||||
|
|
||||||
|
def get_contact_list(self) -> str:
|
||||||
|
contact_list_name = self._get_param("ContactListName")
|
||||||
|
contact_list = self.sesv2_backend.get_contact_list(contact_list_name)
|
||||||
|
return json.dumps(contact_list.response_object)
|
||||||
|
|
||||||
|
def list_contact_lists(self) -> str:
|
||||||
|
contact_lists = self.sesv2_backend.list_contact_lists()
|
||||||
|
return json.dumps(dict(ContactLists=[c.response_object for c in contact_lists]))
|
||||||
|
|
||||||
|
def delete_contact_list(self) -> str:
|
||||||
|
name = self._get_param("ContactListName")
|
||||||
|
self.sesv2_backend.delete_contact_list(name)
|
||||||
|
return json.dumps({})
|
||||||
|
|
||||||
|
def create_contact(self) -> str:
|
||||||
|
contact_list_name = self._get_param("ContactListName")
|
||||||
|
params = get_params_dict(self.data)
|
||||||
|
self.sesv2_backend.create_contact(contact_list_name, params)
|
||||||
|
return json.dumps({})
|
||||||
|
|
||||||
|
def get_contact(self) -> str:
|
||||||
|
email = unquote(self._get_param("EmailAddress"))
|
||||||
|
contact_list_name = self._get_param("ContactListName")
|
||||||
|
contact = self.sesv2_backend.get_contact(email, contact_list_name)
|
||||||
|
return json.dumps(contact.response_object)
|
||||||
|
|
||||||
|
def list_contacts(self) -> str:
|
||||||
|
contact_list_name = self._get_param("ContactListName")
|
||||||
|
contacts = self.sesv2_backend.list_contacts(contact_list_name)
|
||||||
|
return json.dumps(dict(Contacts=[c.response_object for c in contacts]))
|
||||||
|
|
||||||
|
def delete_contact(self) -> str:
|
||||||
|
email = self._get_param("EmailAddress")
|
||||||
|
contact_list_name = self._get_param("ContactListName")
|
||||||
|
self.sesv2_backend.delete_contact(unquote(email), contact_list_name)
|
||||||
|
return json.dumps({})
|
||||||
|
|
||||||
|
|
||||||
|
def get_params_dict(odict: Dict[str, Any]) -> Any:
|
||||||
|
# parsing of these params is nasty, hopefully there is a tidier way
|
||||||
|
return json.loads(list(dict(odict.items()).keys())[0])
|
19
moto/sesv2/urls.py
Normal file
19
moto/sesv2/urls.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
"""sesv2 base URL and path."""
|
||||||
|
from .responses import SESV2Response
|
||||||
|
|
||||||
|
url_bases = [
|
||||||
|
r"https?://email\.(.+)\.amazonaws\.com",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
response = SESV2Response()
|
||||||
|
|
||||||
|
|
||||||
|
url_paths = {
|
||||||
|
"{0}/v2/email/outbound-emails$": response.dispatch,
|
||||||
|
"{0}/v2/email/contact-lists/(?P<name>[^/]+)$": response.dispatch,
|
||||||
|
"{0}/v2/email/contact-lists/(?P<name>[^/]+)/contacts$": response.dispatch,
|
||||||
|
"{0}/v2/email/contact-lists/(?P<name>[^/]+)/contacts/(?P<email>[^/]+)$": response.dispatch,
|
||||||
|
"{0}/v2/email/contact-lists$": response.dispatch,
|
||||||
|
"{0}/v2/.*$": response.dispatch,
|
||||||
|
}
|
@ -61,6 +61,7 @@ def calculate_extended_implementation_coverage():
|
|||||||
operation_names = [
|
operation_names = [
|
||||||
xform_name(op) for op in real_client.meta.service_model.operation_names
|
xform_name(op) for op in real_client.meta.service_model.operation_names
|
||||||
]
|
]
|
||||||
|
|
||||||
for op in operation_names:
|
for op in operation_names:
|
||||||
if moto_client and op in dir(moto_client):
|
if moto_client and op in dir(moto_client):
|
||||||
implemented[op] = getattr(moto_client, op)
|
implemented[op] = getattr(moto_client, op)
|
||||||
|
0
tests/test_sesv2/__init__.py
Normal file
0
tests/test_sesv2/__init__.py
Normal file
13
tests/test_sesv2/test_server.py
Normal file
13
tests/test_sesv2/test_server.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"""Test different server responses."""
|
||||||
|
|
||||||
|
import moto.server as server
|
||||||
|
|
||||||
|
|
||||||
|
def test_sesv2_list():
|
||||||
|
backend = server.create_backend_app("sesv2")
|
||||||
|
test_client = backend.test_client()
|
||||||
|
|
||||||
|
resp = test_client.get("/v2/email/contact-lists")
|
||||||
|
|
||||||
|
assert resp.status_code == 200
|
||||||
|
assert resp.data == b'{"ContactLists": []}'
|
323
tests/test_sesv2/test_sesv2.py
Normal file
323
tests/test_sesv2/test_sesv2.py
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
import boto3
|
||||||
|
from botocore.exceptions import ClientError
|
||||||
|
import pytest
|
||||||
|
from moto import mock_sesv2, mock_ses
|
||||||
|
from ..test_ses.test_ses_boto3 import get_raw_email
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def ses_v1():
|
||||||
|
"""Use this for API calls which exist in v1 but not in v2"""
|
||||||
|
with mock_ses():
|
||||||
|
yield boto3.client("ses", region_name="us-east-1")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_send_email(ses_v1): # pylint: disable=redefined-outer-name
|
||||||
|
# Setup
|
||||||
|
conn = boto3.client("sesv2", region_name="us-east-1")
|
||||||
|
kwargs = dict(
|
||||||
|
FromEmailAddress="test@example.com",
|
||||||
|
Destination={
|
||||||
|
"ToAddresses": ["test_to@example.com"],
|
||||||
|
"CcAddresses": ["test_cc@example.com"],
|
||||||
|
"BccAddresses": ["test_bcc@example.com"],
|
||||||
|
},
|
||||||
|
Content={
|
||||||
|
"Simple": {
|
||||||
|
"Subject": {"Data": "test subject"},
|
||||||
|
"Body": {"Text": {"Data": "test body"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Execute
|
||||||
|
with pytest.raises(ClientError) as e:
|
||||||
|
conn.send_email(**kwargs)
|
||||||
|
assert e.value.response["Error"]["Code"] == "MessageRejected"
|
||||||
|
|
||||||
|
ses_v1.verify_domain_identity(Domain="example.com")
|
||||||
|
conn.send_email(**kwargs)
|
||||||
|
send_quota = ses_v1.get_send_quota()
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
sent_count = int(send_quota["SentLast24Hours"])
|
||||||
|
assert sent_count == 3
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_send_raw_email(ses_v1): # pylint: disable=redefined-outer-name
|
||||||
|
# Setup
|
||||||
|
conn = boto3.client("sesv2", region_name="us-east-1")
|
||||||
|
message = get_raw_email()
|
||||||
|
destination = {
|
||||||
|
"ToAddresses": [x.strip() for x in message["To"].split(",")],
|
||||||
|
}
|
||||||
|
kwargs = dict(
|
||||||
|
FromEmailAddress=message["From"],
|
||||||
|
Destination=destination,
|
||||||
|
Content={"Raw": {"Data": message.as_bytes()}},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Execute
|
||||||
|
ses_v1.verify_email_identity(EmailAddress="test@example.com")
|
||||||
|
conn.send_email(**kwargs)
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
send_quota = ses_v1.get_send_quota()
|
||||||
|
sent_count = int(send_quota["SentLast24Hours"])
|
||||||
|
assert sent_count == 2
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_create_contact_list():
|
||||||
|
# Setup
|
||||||
|
conn = boto3.client("sesv2", region_name="us-east-1")
|
||||||
|
contact_list_name = "test2"
|
||||||
|
|
||||||
|
# Execute
|
||||||
|
conn.create_contact_list(
|
||||||
|
ContactListName=contact_list_name,
|
||||||
|
)
|
||||||
|
result = conn.list_contact_lists()
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
assert len(result["ContactLists"]) == 1
|
||||||
|
assert result["ContactLists"][0]["ContactListName"] == contact_list_name
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_list_contact_lists():
|
||||||
|
# Setup
|
||||||
|
conn = boto3.client("sesv2", region_name="us-east-1")
|
||||||
|
|
||||||
|
# Execute
|
||||||
|
result = conn.list_contact_lists()
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
assert result["ContactLists"] == []
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_get_contact_list():
|
||||||
|
# Setup
|
||||||
|
conn = boto3.client("sesv2", region_name="us-east-1")
|
||||||
|
contact_list_name = "test2"
|
||||||
|
|
||||||
|
# Execute
|
||||||
|
with pytest.raises(ClientError) as e:
|
||||||
|
conn.get_contact_list(ContactListName=contact_list_name)
|
||||||
|
assert e.value.response["Error"]["Code"] == "NotFoundException"
|
||||||
|
assert (
|
||||||
|
e.value.response["Error"]["Message"]
|
||||||
|
== f"List with name: {contact_list_name} doesn't exist."
|
||||||
|
)
|
||||||
|
|
||||||
|
conn.create_contact_list(
|
||||||
|
ContactListName=contact_list_name,
|
||||||
|
)
|
||||||
|
result = conn.get_contact_list(ContactListName=contact_list_name)
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
assert result["ContactListName"] == contact_list_name
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_delete_contact_list():
|
||||||
|
# Setup
|
||||||
|
conn = boto3.client("sesv2", region_name="us-east-1")
|
||||||
|
contact_list_name = "test2"
|
||||||
|
|
||||||
|
# Execute
|
||||||
|
with pytest.raises(ClientError) as e:
|
||||||
|
conn.delete_contact_list(ContactListName=contact_list_name)
|
||||||
|
assert e.value.response["Error"]["Code"] == "NotFoundException"
|
||||||
|
conn.create_contact_list(
|
||||||
|
ContactListName=contact_list_name,
|
||||||
|
)
|
||||||
|
result = conn.list_contact_lists()
|
||||||
|
assert len(result["ContactLists"]) == 1
|
||||||
|
conn.delete_contact_list(
|
||||||
|
ContactListName=contact_list_name,
|
||||||
|
)
|
||||||
|
result = conn.list_contact_lists()
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
assert len(result["ContactLists"]) == 0
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_list_contacts():
|
||||||
|
# Setup
|
||||||
|
conn = boto3.client("sesv2", region_name="us-east-1")
|
||||||
|
contact_list_name = "test2"
|
||||||
|
conn.create_contact_list(
|
||||||
|
ContactListName=contact_list_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Execute
|
||||||
|
result = conn.list_contacts(ContactListName=contact_list_name)
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
assert result["Contacts"] == []
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_create_contact_no_contact_list():
|
||||||
|
# Setup
|
||||||
|
conn = boto3.client("sesv2", region_name="us-east-1")
|
||||||
|
contact_list_name = "test2"
|
||||||
|
email = "test@example.com"
|
||||||
|
|
||||||
|
# Execute
|
||||||
|
with pytest.raises(ClientError) as e:
|
||||||
|
conn.create_contact(
|
||||||
|
ContactListName=contact_list_name,
|
||||||
|
EmailAddress=email,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
assert e.value.response["Error"]["Code"] == "NotFoundException"
|
||||||
|
assert (
|
||||||
|
e.value.response["Error"]["Message"]
|
||||||
|
== f"List with name: {contact_list_name} doesn't exist."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_create_contact():
|
||||||
|
# Setup
|
||||||
|
conn = boto3.client("sesv2", region_name="us-east-1")
|
||||||
|
contact_list_name = "test2"
|
||||||
|
email = "test@example.com"
|
||||||
|
conn.create_contact_list(
|
||||||
|
ContactListName=contact_list_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Execute
|
||||||
|
conn.create_contact(
|
||||||
|
ContactListName=contact_list_name,
|
||||||
|
EmailAddress=email,
|
||||||
|
)
|
||||||
|
|
||||||
|
result = conn.list_contacts(ContactListName=contact_list_name)
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
assert len(result["Contacts"]) == 1
|
||||||
|
assert result["Contacts"][0]["EmailAddress"] == email
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_get_contact_no_contact_list():
|
||||||
|
# Setup
|
||||||
|
conn = boto3.client("sesv2", region_name="us-east-1")
|
||||||
|
contact_list_name = "test2"
|
||||||
|
email = "test@example.com"
|
||||||
|
|
||||||
|
# Execute
|
||||||
|
with pytest.raises(ClientError) as e:
|
||||||
|
conn.get_contact(ContactListName=contact_list_name, EmailAddress=email)
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
assert e.value.response["Error"]["Code"] == "NotFoundException"
|
||||||
|
assert (
|
||||||
|
e.value.response["Error"]["Message"]
|
||||||
|
== f"List with name: {contact_list_name} doesn't exist."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_get_contact():
|
||||||
|
# Setup
|
||||||
|
conn = boto3.client("sesv2", region_name="us-east-1")
|
||||||
|
contact_list_name = "test2"
|
||||||
|
email = "test@example.com"
|
||||||
|
conn.create_contact_list(
|
||||||
|
ContactListName=contact_list_name,
|
||||||
|
)
|
||||||
|
# Execute
|
||||||
|
|
||||||
|
conn.create_contact(
|
||||||
|
ContactListName=contact_list_name,
|
||||||
|
EmailAddress=email,
|
||||||
|
)
|
||||||
|
result = conn.get_contact(ContactListName=contact_list_name, EmailAddress=email)
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
assert result["ContactListName"] == contact_list_name
|
||||||
|
assert result["EmailAddress"] == email
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_get_contact_no_contact():
|
||||||
|
# Setup
|
||||||
|
conn = boto3.client("sesv2", region_name="us-east-1")
|
||||||
|
contact_list_name = "test2"
|
||||||
|
email = "test@example.com"
|
||||||
|
conn.create_contact_list(
|
||||||
|
ContactListName=contact_list_name,
|
||||||
|
)
|
||||||
|
# Execute
|
||||||
|
with pytest.raises(ClientError) as e:
|
||||||
|
conn.get_contact(ContactListName=contact_list_name, EmailAddress=email)
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
assert e.value.response["Error"]["Code"] == "NotFoundException"
|
||||||
|
assert e.value.response["Error"]["Message"] == f"{email} doesn't exist in List."
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_delete_contact_no_contact_list():
|
||||||
|
# Setup
|
||||||
|
conn = boto3.client("sesv2", region_name="us-east-1")
|
||||||
|
contact_list_name = "test2"
|
||||||
|
email = "test@example.com"
|
||||||
|
|
||||||
|
# Execute
|
||||||
|
with pytest.raises(ClientError) as e:
|
||||||
|
conn.delete_contact(ContactListName=contact_list_name, EmailAddress=email)
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
assert e.value.response["Error"]["Code"] == "NotFoundException"
|
||||||
|
assert (
|
||||||
|
e.value.response["Error"]["Message"]
|
||||||
|
== f"List with name: {contact_list_name} doesn't exist."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_delete_contact_no_contact():
|
||||||
|
# Setup
|
||||||
|
conn = boto3.client("sesv2", region_name="us-east-1")
|
||||||
|
contact_list_name = "test2"
|
||||||
|
email = "test@example.com"
|
||||||
|
|
||||||
|
# Execute
|
||||||
|
conn.create_contact_list(ContactListName=contact_list_name)
|
||||||
|
|
||||||
|
with pytest.raises(ClientError) as e:
|
||||||
|
conn.delete_contact(ContactListName=contact_list_name, EmailAddress=email)
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
assert e.value.response["Error"]["Code"] == "NotFoundException"
|
||||||
|
assert e.value.response["Error"]["Message"] == f"{email} doesn't exist in List."
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sesv2
|
||||||
|
def test_delete_contact():
|
||||||
|
# Setup
|
||||||
|
conn = boto3.client("sesv2", region_name="us-east-1")
|
||||||
|
contact_list_name = "test2"
|
||||||
|
email = "test@example.com"
|
||||||
|
|
||||||
|
# Execute
|
||||||
|
conn.create_contact_list(ContactListName=contact_list_name)
|
||||||
|
conn.create_contact(ContactListName=contact_list_name, EmailAddress=email)
|
||||||
|
result = conn.list_contacts(ContactListName=contact_list_name)
|
||||||
|
assert len(result["Contacts"]) == 1
|
||||||
|
|
||||||
|
conn.delete_contact(ContactListName=contact_list_name, EmailAddress=email)
|
||||||
|
result = conn.list_contacts(ContactListName=contact_list_name)
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
assert len(result["Contacts"]) == 0
|
Loading…
Reference in New Issue
Block a user