Repository: getmoto/moto
Pull request #7525 (2024-03-26 21:46:34)

Prep release 5.0.4

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/getmoto/moto/pull/7525?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 94.07%. Comparing base [(`9aef694`)](https://app.codecov.io/gh/getmoto/moto/commit/9aef6944da6a6f1b84be99cefb34f1724e6ca58f?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) to head [(`afc1760`)](https://app.codecov.io/gh/getmoto/moto/pull/7525?dropdown=coverage&src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto).
> Report is 139 commits behind head on master.


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #7525      +/-   ##
==========================================
- Coverage   95.88%   94.07%   -1.82%     
==========================================
  Files         843     1070     +227     
  Lines       82578    91824    +9246     
==========================================
+ Hits        79178    86379    +7201     
- Misses       3400     5445    +2045     
```

| [Flag](https://app.codecov.io/gh/getmoto/moto/pull/7525/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) | Coverage Δ | |
|---|---|---|
| [servertests](https://app.codecov.io/gh/getmoto/moto/pull/7525/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) | `29.57% <0.00%> (-2.96%)` | :arrow_down: |
| [unittests](https://app.codecov.io/gh/getmoto/moto/pull/7525/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) | `94.03% <100.00%> (-1.81%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto#carryforward-flags-in-the-pull-request-comment) to find out more.


</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/getmoto/moto/pull/7525?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto).


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e9b5e1ebc..cd252b650 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,76 @@
 Moto Changelog
 ==============
 
+5.0.4
+-----
+Docker Digest for 5.0.4: <autopopulateddigest>
+
+    General:
+        * Lambda: The results of a Dockerless invocation can now be configured.
+          See http://docs.getmoto.org/en/latest/docs/services/lambda.html
+
+        * StepFunctions can now execute the provided StepFunctionMachine (opt-in), instead of returning static data (still the default).
+          See http://docs.getmoto.org/en/latest/docs/services/stepfunctions.html
+
+    New Service:
+        * ElastiCache:
+            * list_tags_for_resource()
+
+        * ResilienceHub:
+            * create_app()
+            * create_app_version_app_component()
+            * create_app_version_resource()
+            * create_resiliency_policy()
+            * describe_app()
+            * describe_resiliency_policy()
+            * import_resources_to_draft_app_version()
+            * list_app_assessments()
+            * list_app_version_app_components()
+            * list_app_version_resources()
+            * list_app_versions()
+            * list_apps()
+            * list_resiliency_policies()
+            * list_tags_for_resource()
+            * publish_app_version()
+            * tag_resource()
+            * untag_resource()
+
+        * Workspaces:
+            * create_tags()
+            * create_workspace_image()
+            * create_workspaces()
+            * deregister_workspace_directory()
+            * describe_client_properties()
+            * describe_tags()
+            * describe_workspace_directories()
+            * describe_workspace_image_permissions()
+            * describe_workspace_images()
+            * describe_workspaces()
+            * modify_client_properties()
+            * modify_selfservice_permissions()
+            * modify_workspace_creation_properties()
+            * register_workspace_directory()
+            * update_workspace_image_permission()
+
+    Miscellaneous:
+        * APIGateway: update_usage_plan() now supports some remove-operations
+        * Autoscaling: describe_auto_scaling_groups() now returns a dynamic CreatedTime
+        * CloudFormation: Outputs now support Conditions
+        * CloudFormation: Outputs now return Descriptions
+        * CognitoIDP: admin_update_user_attributes() and admin_delete_user_attributes now correctly update the UserLastModifiedDate
+        * DynamoDB: query() no longer requires the LastEvaluatedKey to exist
+        * EC2: describe_vpc_endpoint_services() now supports all services
+        * Kinesis: list_streams() now returns StreamSummaries
+        * Lambda: get_policy() now throws an error when no statements exist
+        * ResourceGroupsTaggingAPI now supports DynamoDB tables
+        * ResourceGroupsTaggingAPI now supports SSM documents
+        * S3: EventBridge notifications are now supported for ObjectRestore:Post
+        * S3: restore_object() now contains limited validation when supplying both Days- and Type-argument
+        * S3: select_object_content() now supports Compressed requests and CSV responses
+        * SecretsManager: list_secrets() now handles negative matches correctly
+        * SNS: delete_endpoint() is now an idempotent operation, just like AWS
+
+
 5.0.3
 -----
 Docker Digest for 5.0.3: _sha256:032d8ead42f289d9700e9bc844c6d264575ad11b3f6c22cc76d65ff638c8c7bd_
diff --git a/IMPLEMENTATION_COVERAGE.md b/IMPLEMENTATION_COVERAGE.md
index a00754251..b9ffea9a2 100644
--- a/IMPLEMENTATION_COVERAGE.md
+++ b/IMPLEMENTATION_COVERAGE.md
@@ -2870,7 +2870,7 @@
 
 ## elasticache
 <details>
-<summary>8% implemented</summary>
+<summary>9% implemented</summary>
 
 - [ ] add_tags_to_resource
 - [ ] authorize_cache_security_group_ingress
@@ -2928,7 +2928,7 @@
 - [ ] increase_node_groups_in_global_replication_group
 - [ ] increase_replica_count
 - [ ] list_allowed_node_type_modifications
-- [ ] list_tags_for_resource
+- [X] list_tags_for_resource
 - [ ] modify_cache_cluster
 - [ ] modify_cache_parameter_group
 - [ ] modify_cache_subnet_group
@@ -8015,6 +8015,85 @@
 - [X] update_web_acl
 </details>
 
+## workspaces
+<details>
+<summary>20% implemented</summary>
+
+- [ ] associate_connection_alias
+- [ ] associate_ip_groups
+- [ ] associate_workspace_application
+- [ ] authorize_ip_rules
+- [ ] copy_workspace_image
+- [ ] create_connect_client_add_in
+- [ ] create_connection_alias
+- [ ] create_ip_group
+- [ ] create_standby_workspaces
+- [X] create_tags
+- [ ] create_updated_workspace_image
+- [ ] create_workspace_bundle
+- [X] create_workspace_image
+- [X] create_workspaces
+- [ ] delete_client_branding
+- [ ] delete_connect_client_add_in
+- [ ] delete_connection_alias
+- [ ] delete_ip_group
+- [ ] delete_tags
+- [ ] delete_workspace_bundle
+- [ ] delete_workspace_image
+- [ ] deploy_workspace_applications
+- [X] deregister_workspace_directory
+- [ ] describe_account
+- [ ] describe_account_modifications
+- [ ] describe_application_associations
+- [ ] describe_applications
+- [ ] describe_bundle_associations
+- [ ] describe_client_branding
+- [X] describe_client_properties
+- [ ] describe_connect_client_add_ins
+- [ ] describe_connection_alias_permissions
+- [ ] describe_connection_aliases
+- [ ] describe_image_associations
+- [ ] describe_ip_groups
+- [X] describe_tags
+- [ ] describe_workspace_associations
+- [ ] describe_workspace_bundles
+- [X] describe_workspace_directories
+- [X] describe_workspace_image_permissions
+- [X] describe_workspace_images
+- [ ] describe_workspace_snapshots
+- [X] describe_workspaces
+- [ ] describe_workspaces_connection_status
+- [ ] disassociate_connection_alias
+- [ ] disassociate_ip_groups
+- [ ] disassociate_workspace_application
+- [ ] import_client_branding
+- [ ] import_workspace_image
+- [ ] list_available_management_cidr_ranges
+- [ ] migrate_workspace
+- [ ] modify_account
+- [ ] modify_certificate_based_auth_properties
+- [X] modify_client_properties
+- [ ] modify_saml_properties
+- [X] modify_selfservice_permissions
+- [ ] modify_workspace_access_properties
+- [X] modify_workspace_creation_properties
+- [ ] modify_workspace_properties
+- [ ] modify_workspace_state
+- [ ] reboot_workspaces
+- [ ] rebuild_workspaces
+- [X] register_workspace_directory
+- [ ] restore_workspace
+- [ ] revoke_ip_rules
+- [ ] start_workspaces
+- [ ] stop_workspaces
+- [ ] terminate_workspaces
+- [ ] update_connect_client_add_in
+- [ ] update_connection_alias_permission
+- [ ] update_rules_of_ip_group
+- [ ] update_workspace_bundle
+- [X] update_workspace_image_permission
+</details>
+
 ## Unimplemented:
 <details>
 
@@ -8269,7 +8348,6 @@
 - worklink
 - workmail
 - workmailmessageflow
-- workspaces
 - workspaces-thin-client
 - workspaces-web
 - xray
diff --git a/docs/docs/configuration/index.rst b/docs/docs/configuration/index.rst
index 4718b94dc..106986b90 100644
--- a/docs/docs/configuration/index.rst
+++ b/docs/docs/configuration/index.rst
@@ -65,7 +65,8 @@ The following options can also be configured when running the MotoServer:
 
     options = {
         "batch": {"use_docker": True},
-        "lambda": {"use_docker": True}
+        "lambda": {"use_docker": True},
+        "stepfunctions": {"execute_state_machine": True}
     }
     requests.post(f"http://localhost:5000/moto-api/config", json=options)
 
diff --git a/docs/docs/services/apigateway.rst b/docs/docs/services/apigateway.rst
index 4d3797589..4a7a15239 100644
--- a/docs/docs/services/apigateway.rst
+++ b/docs/docs/services/apigateway.rst
@@ -155,7 +155,7 @@ apigateway
         The following PatchOperations are currently supported:
         add    : Everything except /apiStages/{apidId:stageName}/throttle/ and children
         replace: Everything except /apiStages/{apidId:stageName}/throttle/ and children
-        remove : Nothing yet
+        remove : Everything except /apiStages/{apidId:stageName}/throttle/ and children
         copy   : Nothing yet
         
 
diff --git a/docs/docs/services/athena.rst b/docs/docs/services/athena.rst
index 67f14ea67..12145c85a 100644
--- a/docs/docs/services/athena.rst
+++ b/docs/docs/services/athena.rst
@@ -78,7 +78,7 @@ athena
                 ],
             }
             resp = requests.post(
-                "http://motoapi.amazonaws.com:5000/moto-api/static/athena/query-results",
+                "http://motoapi.amazonaws.com/moto-api/static/athena/query-results",
                 json=expected_results,
             )
             assert resp.status_code == 201
diff --git a/docs/docs/services/ce.rst b/docs/docs/services/ce.rst
index ace021264..ee3b41d83 100644
--- a/docs/docs/services/ce.rst
+++ b/docs/docs/services/ce.rst
@@ -74,7 +74,7 @@ ce
                 ]
             }
             resp = requests.post(
-                "http://motoapi.amazonaws.com:5000/moto-api/static/ce/cost-and-usage-results",
+                "http://motoapi.amazonaws.com/moto-api/static/ce/cost-and-usage-results",
                 json=expected_results,
             )
             assert resp.status_code == 201
diff --git a/docs/docs/services/elasticache.rst b/docs/docs/services/elasticache.rst
index f11f21dfd..b250acc49 100644
--- a/docs/docs/services/elasticache.rst
+++ b/docs/docs/services/elasticache.rst
@@ -77,7 +77,7 @@ elasticache
 - [ ] increase_node_groups_in_global_replication_group
 - [ ] increase_replica_count
 - [ ] list_allowed_node_type_modifications
-- [ ] list_tags_for_resource
+- [X] list_tags_for_resource
 - [ ] modify_cache_cluster
 - [ ] modify_cache_parameter_group
 - [ ] modify_cache_subnet_group
diff --git a/docs/docs/services/inspector2.rst b/docs/docs/services/inspector2.rst
index ccde2b5d3..56c38f19e 100644
--- a/docs/docs/services/inspector2.rst
+++ b/docs/docs/services/inspector2.rst
@@ -82,7 +82,7 @@ inspector2
                 "region": "us-east-1",  # This is the default - can be omitted
             }
             resp = requests.post(
-                "http://motoapi.amazonaws.com:5000/moto-api/static/inspector2/findings-results",
+                "http://motoapi.amazonaws.com/moto-api/static/inspector2/findings-results",
                 json=findings,
             )
 
diff --git a/docs/docs/services/lambda.rst b/docs/docs/services/lambda.rst
index a4e91e2ac..40045f6e4 100644
--- a/docs/docs/services/lambda.rst
+++ b/docs/docs/services/lambda.rst
@@ -81,15 +81,15 @@ lambda
 
             expected_results = {"results": ["test", "test 2"], "region": "us-east-1"}
             resp = requests.post(
-                    "http://motoapi.amazonaws.com:5000/moto-api/static/lambda-simple/response",
-                    json=expected_results,
-                )
-
+                "http://motoapi.amazonaws.com/moto-api/static/lambda-simple/response",
+                json=expected_results
+            )
             assert resp.status_code == 201
 
             client = boto3.client("lambda", region_name="us-east-1")
             resp = client.invoke(...) # resp["Payload"].read().decode() == "test"
             resp = client.invoke(...) # resp["Payload"].read().decode() == "test2"
+        
 
 - [ ] invoke_async
 - [ ] invoke_with_response_stream
diff --git a/docs/docs/services/rds-data.rst b/docs/docs/services/rds-data.rst
index 07ec2a91f..77b72519b 100644
--- a/docs/docs/services/rds-data.rst
+++ b/docs/docs/services/rds-data.rst
@@ -47,7 +47,7 @@ rds-data
                 ],
             }
             resp = requests.post(
-                "http://motoapi.amazonaws.com:5000/moto-api/static/rds-data/statement-results",
+                "http://motoapi.amazonaws.com/moto-api/static/rds-data/statement-results",
                 json=expected_results,
             )
             assert resp.status_code == 201
diff --git a/docs/docs/services/resourcegroupstaggingapi.rst b/docs/docs/services/resourcegroupstaggingapi.rst
index 8a675e343..90c46ab77 100644
--- a/docs/docs/services/resourcegroupstaggingapi.rst
+++ b/docs/docs/services/resourcegroupstaggingapi.rst
@@ -22,7 +22,7 @@ resourcegroupstaggingapi
 - [ ] start_report_creation
 - [X] tag_resources
   
-        Only Logs and RDS resources are currently supported
+        Only DynamoDB, Logs and RDS resources are currently supported
         
 
 - [ ] untag_resources
diff --git a/docs/docs/services/s3.rst b/docs/docs/services/s3.rst
index d7973040d..155e1ff07 100644
--- a/docs/docs/services/s3.rst
+++ b/docs/docs/services/s3.rst
@@ -114,6 +114,7 @@ s3
          - 's3:ObjectCreated:Post'
          - 's3:ObjectCreated:Put'
          - 's3:ObjectDeleted'
+         - 's3:ObjectRestore:Post'
         
 
 - [X] put_bucket_ownership_controls
diff --git a/docs/docs/services/sagemaker-runtime.rst b/docs/docs/services/sagemaker-runtime.rst
index 68c711f83..073331ff8 100644
--- a/docs/docs/services/sagemaker-runtime.rst
+++ b/docs/docs/services/sagemaker-runtime.rst
@@ -42,7 +42,7 @@ sagemaker-runtime
                 ],
             }
             requests.post(
-                "http://motoapi.amazonaws.com:5000/moto-api/static/sagemaker/endpoint-results",
+                "http://motoapi.amazonaws.com/moto-api/static/sagemaker/endpoint-results",
                 json=expected_results,
             )
 
diff --git a/docs/docs/services/workspaces.rst b/docs/docs/services/workspaces.rst
new file mode 100644
index 000000000..0b57da593
--- /dev/null
+++ b/docs/docs/services/workspaces.rst
@@ -0,0 +1,96 @@
+.. _implementedservice_workspaces:
+
+.. |start-h3| raw:: html
+
+    <h3>
+
+.. |end-h3| raw:: html
+
+    </h3>
+
+==========
+workspaces
+==========
+
+.. autoclass:: moto.workspaces.models.WorkSpacesBackend
+
+|start-h3| Implemented features for this service |end-h3|
+
+- [ ] associate_connection_alias
+- [ ] associate_ip_groups
+- [ ] associate_workspace_application
+- [ ] authorize_ip_rules
+- [ ] copy_workspace_image
+- [ ] create_connect_client_add_in
+- [ ] create_connection_alias
+- [ ] create_ip_group
+- [ ] create_standby_workspaces
+- [X] create_tags
+- [ ] create_updated_workspace_image
+- [ ] create_workspace_bundle
+- [X] create_workspace_image
+- [X] create_workspaces
+- [ ] delete_client_branding
+- [ ] delete_connect_client_add_in
+- [ ] delete_connection_alias
+- [ ] delete_ip_group
+- [ ] delete_tags
+- [ ] delete_workspace_bundle
+- [ ] delete_workspace_image
+- [ ] deploy_workspace_applications
+- [X] deregister_workspace_directory
+  Deregister Workspace Directory with the matching ID.
+
+- [ ] describe_account
+- [ ] describe_account_modifications
+- [ ] describe_application_associations
+- [ ] describe_applications
+- [ ] describe_bundle_associations
+- [ ] describe_client_branding
+- [X] describe_client_properties
+- [ ] describe_connect_client_add_ins
+- [ ] describe_connection_alias_permissions
+- [ ] describe_connection_aliases
+- [ ] describe_image_associations
+- [ ] describe_ip_groups
+- [X] describe_tags
+- [ ] describe_workspace_associations
+- [ ] describe_workspace_bundles
+- [X] describe_workspace_directories
+  Return info on all directories or directories with matching IDs.
+
+- [X] describe_workspace_image_permissions
+- [X] describe_workspace_images
+- [ ] describe_workspace_snapshots
+- [X] describe_workspaces
+- [ ] describe_workspaces_connection_status
+- [ ] disassociate_connection_alias
+- [ ] disassociate_ip_groups
+- [ ] disassociate_workspace_application
+- [ ] import_client_branding
+- [ ] import_workspace_image
+- [ ] list_available_management_cidr_ranges
+- [ ] migrate_workspace
+- [ ] modify_account
+- [ ] modify_certificate_based_auth_properties
+- [X] modify_client_properties
+- [ ] modify_saml_properties
+- [X] modify_selfservice_permissions
+- [ ] modify_workspace_access_properties
+- [X] modify_workspace_creation_properties
+- [ ] modify_workspace_properties
+- [ ] modify_workspace_state
+- [ ] reboot_workspaces
+- [ ] rebuild_workspaces
+- [X] register_workspace_directory
+- [ ] restore_workspace
+- [ ] revoke_ip_rules
+- [ ] start_workspaces
+- [ ] stop_workspaces
+- [ ] terminate_workspaces
+- [ ] update_connect_client_add_in
+- [ ] update_connection_alias_permission
+- [ ] update_rules_of_ip_group
+- [ ] update_workspace_bundle
+- [X] update_workspace_image_permission
+
diff --git a/moto/athena/models.py b/moto/athena/models.py
index 327405c4f..b78a0bf06 100644
--- a/moto/athena/models.py
+++ b/moto/athena/models.py
@@ -259,7 +259,7 @@ class AthenaBackend(BaseBackend):
                 ],
             }
             resp = requests.post(
-                "http://motoapi.amazonaws.com:5000/moto-api/static/athena/query-results",
+                "http://motoapi.amazonaws.com/moto-api/static/athena/query-results",
                 json=expected_results,
             )
             assert resp.status_code == 201
diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py
index 37e9c4c1f..aeefc988b 100644
--- a/moto/awslambda/models.py
+++ b/moto/awslambda/models.py
@@ -2375,6 +2375,26 @@ class LambdaBackend(BaseBackend):
     ) -> Optional[Union[str, bytes]]:
         """
         Invoking a Function with PackageType=Image is not yet supported.
+
+        Invoking a Funcation against Lambda without docker now supports customised responses, the default being `Simple Lambda happy path OK`.
+        You can use a dedicated API to override this, by configuring a queue of expected results.
+
+        A request to `invoke` will take the first result from that queue.
+
+        Configure this queue by making an HTTP request to `/moto-api/static/lambda-simple/response`. An example invocation looks like this:
+
+        .. sourcecode:: python
+
+            expected_results = {"results": ["test", "test 2"], "region": "us-east-1"}
+            resp = requests.post(
+                "http://motoapi.amazonaws.com/moto-api/static/lambda-simple/response",
+                json=expected_results
+            )
+            assert resp.status_code == 201
+
+            client = boto3.client("lambda", region_name="us-east-1")
+            resp = client.invoke(...) # resp["Payload"].read().decode() == "test"
+            resp = client.invoke(...) # resp["Payload"].read().decode() == "test2"
         """
         fn = self.get_function(function_name, qualifier)
         payload = fn.invoke(body, headers, response_headers)
diff --git a/moto/awslambda_simple/models.py b/moto/awslambda_simple/models.py
index 12381a98c..536082b7e 100644
--- a/moto/awslambda_simple/models.py
+++ b/moto/awslambda_simple/models.py
@@ -23,7 +23,7 @@ class LambdaSimpleBackend(LambdaBackend):
         headers: Any,
         response_headers: Any,
     ) -> Optional[Union[str, bytes]]:
-        default_result = "Simple Lambda happy path OK"
+        default_result = body or "Simple Lambda happy path OK"
         if self.lambda_simple_results_queue:
             default_result = self.lambda_simple_results_queue.pop(0)
         return str.encode(default_result)
diff --git a/moto/ce/models.py b/moto/ce/models.py
index add58e3c0..6bba495c1 100644
--- a/moto/ce/models.py
+++ b/moto/ce/models.py
@@ -191,7 +191,7 @@ class CostExplorerBackend(BaseBackend):
                 ]
             }
             resp = requests.post(
-                "http://motoapi.amazonaws.com:5000/moto-api/static/ce/cost-and-usage-results",
+                "http://motoapi.amazonaws.com/moto-api/static/ce/cost-and-usage-results",
                 json=expected_results,
             )
             assert resp.status_code == 201
diff --git a/moto/inspector2/models.py b/moto/inspector2/models.py
index 53de199c8..f2e797e11 100644
--- a/moto/inspector2/models.py
+++ b/moto/inspector2/models.py
@@ -196,7 +196,7 @@ class Inspector2Backend(BaseBackend):
                 "region": "us-east-1",  # This is the default - can be omitted
             }
             resp = requests.post(
-                "http://motoapi.amazonaws.com:5000/moto-api/static/inspector2/findings-results",
+                "http://motoapi.amazonaws.com/moto-api/static/inspector2/findings-results",
                 json=findings,
             )
 
diff --git a/moto/rdsdata/models.py b/moto/rdsdata/models.py
index 17ad7453f..ae0c32c22 100644
--- a/moto/rdsdata/models.py
+++ b/moto/rdsdata/models.py
@@ -63,7 +63,7 @@ class RDSDataServiceBackend(BaseBackend):
                 ],
             }
             resp = requests.post(
-                "http://motoapi.amazonaws.com:5000/moto-api/static/rds-data/statement-results",
+                "http://motoapi.amazonaws.com/moto-api/static/rds-data/statement-results",
                 json=expected_results,
             )
             assert resp.status_code == 201
diff --git a/moto/s3/models.py b/moto/s3/models.py
index af925ebf3..b4ef6cc2a 100644
--- a/moto/s3/models.py
+++ b/moto/s3/models.py
@@ -2379,6 +2379,7 @@ class S3Backend(BaseBackend, CloudWatchMetricProvider):
          - 's3:ObjectCreated:Post'
          - 's3:ObjectCreated:Put'
          - 's3:ObjectDeleted'
+         - 's3:ObjectRestore:Post'
         """
         bucket = self.get_bucket(bucket_name)
         bucket.set_notification_configuration(notification_config)


Test patch:
diff --git a/tests/test_awslambda_simple/test_lambda_simple.py b/tests/test_awslambda_simple/test_lambda_simple.py
index be4454c28..5232dfa60 100644
--- a/tests/test_awslambda_simple/test_lambda_simple.py
+++ b/tests/test_awslambda_simple/test_lambda_simple.py
@@ -41,6 +41,13 @@ def test_run_function_no_log():
     # Execute
     result = client.invoke(FunctionName=FUNCTION_NAME, Payload=json.dumps(payload))
 
+    # Verify
+    assert result["StatusCode"] == 200
+    assert json.loads(result["Payload"].read().decode("utf-8")) == payload
+
+    # Execute
+    result = client.invoke(FunctionName=FUNCTION_NAME)
+
     # Verify
     assert result["StatusCode"] == 200
     assert result["Payload"].read().decode("utf-8") == "Simple Lambda happy path OK"