Repository: getmoto/moto
Pull request #5951 (2023-02-20 01:18:53)

Enhancement - Add policy to update rest api for apigateway
- Add the capacity to update ("replace" operation) the **policy** attribute in **update_rest_api** endpoint.
- Enhancement and updating the tests.


Patch:
diff --git a/moto/apigateway/models.py b/moto/apigateway/models.py
index 93fd225f6..c6d8a1680 100644
--- a/moto/apigateway/models.py
+++ b/moto/apigateway/models.py
@@ -1070,6 +1070,8 @@ class RestAPI(CloudFormationModel):
                     self.binaryMediaTypes = [value]
                 if to_path(self.PROP_DISABLE_EXECUTE_API_ENDPOINT) in path:
                     self.disableExecuteApiEndpoint = bool(value)
+                if to_path(self.PROP_POLICY) in path:
+                    self.policy = value
             elif operaton == self.OPERATION_ADD:
                 if to_path(self.PROP_BINARY_MEDIA_TYPES) in path:
                     self.binaryMediaTypes.append(value)
diff --git a/moto/batch/models.py b/moto/batch/models.py
index 5bd751ab8..97ea23945 100644
--- a/moto/batch/models.py
+++ b/moto/batch/models.py
@@ -606,7 +606,12 @@ class Job(threading.Thread, BaseModel, DockerModel, ManagedState):
         """
         try:
             import docker
+        except ImportError as err:
+            logger.error(f"Failed to run AWS Batch container {self.name}. Error {err}")
+            self._mark_stopped(success=False)
+            return
 
+        try:
             containers: List[docker.models.containers.Container] = []
 
             self.advance()
diff --git a/moto/core/models.py b/moto/core/models.py
index 68497694c..58c3b24f3 100644
--- a/moto/core/models.py
+++ b/moto/core/models.py
@@ -64,10 +64,12 @@ class BaseMockAWS:
         if self.__class__.nested_count == 0:
             self.reset()  # type: ignore[attr-defined]
 
-    def __call__(self, func: Callable[..., Any], reset: bool = True) -> Any:
+    def __call__(
+        self, func: Callable[..., Any], reset: bool = True, remove_data: bool = True
+    ) -> Any:
         if inspect.isclass(func):
             return self.decorate_class(func)
-        return self.decorate_callable(func, reset)
+        return self.decorate_callable(func, reset, remove_data)
 
     def __enter__(self) -> "BaseMockAWS":
         self.start()
@@ -89,7 +91,7 @@ class BaseMockAWS:
 
         self.enable_patching(reset)  # type: ignore[attr-defined]
 
-    def stop(self) -> None:
+    def stop(self, remove_data: bool = True) -> None:
         self.__class__.nested_count -= 1
 
         if self.__class__.nested_count < 0:
@@ -105,18 +107,23 @@ class BaseMockAWS:
                     pass
                 self.unmock_env_variables()
                 self.__class__.mocks_active = False
-                reset_model_data()
+                if remove_data:
+                    # Reset the data across all backends
+                    for backend in self.backends.values():
+                        backend.reset()
+                    # Remove references to all model instances that were created
+                    reset_model_data()
             self.disable_patching()  # type: ignore[attr-defined]
 
     def decorate_callable(
-        self, func: Callable[..., CALLABLE_RETURN], reset: bool
+        self, func: Callable[..., CALLABLE_RETURN], reset: bool, remove_data: bool
     ) -> Callable[..., CALLABLE_RETURN]:
         def wrapper(*args: Any, **kwargs: Any) -> CALLABLE_RETURN:
             self.start(reset=reset)
             try:
                 result = func(*args, **kwargs)
             finally:
-                self.stop()
+                self.stop(remove_data=remove_data)
             return result
 
         functools.update_wrapper(wrapper, func)
@@ -173,15 +180,18 @@ class BaseMockAWS:
                 # Special case for UnitTests-class
                 is_test_method = attr.startswith(unittest.TestLoader.testMethodPrefix)
                 should_reset = False
+                should_remove_data = False
                 if attr in ["setUp", "setup_method"]:
                     should_reset = True
                 elif not has_setup_method and is_test_method:
                     should_reset = True
+                    should_remove_data = True
                 else:
                     # Method is unrelated to the test setup
                     # Method is a test, but was already reset while executing the setUp-method
                     pass
-                setattr(klass, attr, self(attr_value, reset=should_reset))
+                kwargs = {"reset": should_reset, "remove_data": should_remove_data}
+                setattr(klass, attr, self(attr_value, **kwargs))
             except TypeError:
                 # Sometimes we can't set this for built-in types
                 continue
diff --git a/moto/core/responses.py b/moto/core/responses.py
index ccffe4332..14e892b18 100644
--- a/moto/core/responses.py
+++ b/moto/core/responses.py
@@ -130,10 +130,14 @@ class ActionAuthenticatorMixin(object):
             ActionAuthenticatorMixin.request_count
             >= settings.INITIAL_NO_AUTH_ACTION_COUNT
         ):
+            parsed_url = urlparse(self.uri)  # type: ignore[attr-defined]
+            path = parsed_url.path
+            if parsed_url.query:
+                path += "?" + parsed_url.query
             iam_request = iam_request_cls(
                 account_id=self.current_account,  # type: ignore[attr-defined]
                 method=self.method,  # type: ignore[attr-defined]
-                path=self.path,  # type: ignore[attr-defined]
+                path=path,
                 data=self.data,  # type: ignore[attr-defined]
                 headers=self.headers,  # type: ignore[attr-defined]
             )
diff --git a/moto/dynamodb/models/table.py b/moto/dynamodb/models/table.py
index b520e24f4..1be961410 100644
--- a/moto/dynamodb/models/table.py
+++ b/moto/dynamodb/models/table.py
@@ -843,6 +843,12 @@ class Table(CloudFormationModel):
             if passes_all_conditions:
                 results.append(item)
 
+        results = copy.deepcopy(results)
+        if index_name:
+            index = self.get_index(index_name)
+            for result in results:
+                index.project(result)
+
         results, last_evaluated_key = self._trim_results(
             results, limit, exclusive_start_key, scanned_index=index_name
         )
diff --git a/moto/ec2/models/subnets.py b/moto/ec2/models/subnets.py
index 96de49faa..0835e8cc8 100644
--- a/moto/ec2/models/subnets.py
+++ b/moto/ec2/models/subnets.py
@@ -197,6 +197,8 @@ class Subnet(TaggedEC2Resource, CloudFormationModel):
 
         return new_ip
 
+    # EFS calls this method as request_ip(str, MountTarget)
+    # So technically it's not just Instances that are stored
     def request_ip(self, ip: str, instance: "Instance") -> None:
         if ipaddress.ip_address(ip) not in self.cidr:
             raise Exception(f"IP does not fall in the subnet CIDR of {self.cidr}")
diff --git a/moto/efs/exceptions.py b/moto/efs/exceptions.py
index f46bd9350..92b8829cc 100644
--- a/moto/efs/exceptions.py
+++ b/moto/efs/exceptions.py
@@ -8,7 +8,7 @@ class EFSError(JsonRESTError):
 class AccessPointNotFound(EFSError):
     code = 404
 
-    def __init__(self, access_point_id):
+    def __init__(self, access_point_id: str):
         super().__init__(
             "AccessPointNotFound", f"Access Point {access_point_id} does not exist."
         )
@@ -17,93 +17,83 @@ class AccessPointNotFound(EFSError):
 class FileSystemAlreadyExists(EFSError):
     code = 409
 
-    def __init__(self, creation_token, *args, **kwargs):
+    def __init__(self, creation_token: str):
         super().__init__(
             "FileSystemAlreadyExists",
             f"File system with {creation_token} already exists.",
-            *args,
-            **kwargs,
         )
 
 
 class FileSystemNotFound(EFSError):
     code = 404
 
-    def __init__(self, file_system_id, *args, **kwargs):
+    def __init__(self, file_system_id: str):
         super().__init__(
             "FileSystemNotFound",
             f"File system {file_system_id} does not exist.",
-            *args,
-            **kwargs,
         )
 
 
 class FileSystemInUse(EFSError):
     code = 409
 
-    def __init__(self, msg, *args, **kwargs):
-        super().__init__("FileSystemInUse", msg, *args, **kwargs)
+    def __init__(self, msg: str):
+        super().__init__("FileSystemInUse", msg)
 
 
 class MountTargetConflict(EFSError):
     code = 409
 
-    def __init__(self, msg, *args, **kwargs):
-        super().__init__("MountTargetConflict", msg, *args, **kwargs)
+    def __init__(self, msg: str):
+        super().__init__("MountTargetConflict", msg)
 
 
 class MountTargetNotFound(EFSError):
     code = 404
 
-    def __init__(self, mount_target_id, *args, **kwargs):
+    def __init__(self, mount_target_id: str):
         super().__init__(
             "MountTargetNotFound",
             f"Mount target '{mount_target_id}' does not exist.",
-            *args,
-            **kwargs,
         )
 
 
 class BadRequest(EFSError):
     code = 400
 
-    def __init__(self, msg, *args, **kwargs):
-        super().__init__("BadRequest", msg, *args, **kwargs)
+    def __init__(self, msg: str):
+        super().__init__("BadRequest", msg)
 
 
 class PolicyNotFound(EFSError):
     code = 404
 
-    def __init__(self, *args, **kwargs):
-        super().__init__("PolicyNotFound", *args, **kwargs)
+    def __init__(self, msg: str):
+        super().__init__("PolicyNotFound", msg)
 
 
 class SubnetNotFound(EFSError):
     code = 404
 
-    def __init__(self, subnet_id, *args, **kwargs):
+    def __init__(self, subnet_id: str):
         super().__init__(
             "SubnetNotFound",
             f"The subnet ID '{subnet_id}' does not exist",
-            *args,
-            **kwargs,
         )
 
 
 class SecurityGroupNotFound(EFSError):
     code = 404
 
-    def __init__(self, security_group_id, *args, **kwargs):
+    def __init__(self, security_group_id: str):
         super().__init__(
             "SecurityGroupNotFound",
             f"The SecurityGroup ID '{security_group_id}' does not exist",
-            *args,
-            **kwargs,
         )
 
 
 class SecurityGroupLimitExceeded(EFSError):
     code = 400
 
-    def __init__(self, msg, *args, **kwargs):
-        super().__init__("SecurityGroupLimitExceeded", msg, *args, **kwargs)
+    def __init__(self, msg: str):
+        super().__init__("SecurityGroupLimitExceeded", msg)
diff --git a/moto/efs/models.py b/moto/efs/models.py
index 6fee71b66..90bae3e1e 100644
--- a/moto/efs/models.py
+++ b/moto/efs/models.py
@@ -7,10 +7,13 @@ https://docs.aws.amazon.com/efs/latest/ug/whatisefs.html
 import json
 import time
 from copy import deepcopy
+from typing import Any, Dict, List, Optional, Tuple, Set, Iterator, Union
 
 from moto.core import BaseBackend, BackendDict, BaseModel, CloudFormationModel
 from moto.core.utils import camelcase_to_underscores, underscores_to_camelcase
 from moto.ec2 import ec2_backends
+from moto.ec2.models.elastic_network_interfaces import NetworkInterface
+from moto.ec2.models.subnets import Subnet
 from moto.ec2.exceptions import InvalidSubnetIdError
 from moto.efs.exceptions import (
     AccessPointNotFound,
@@ -30,25 +33,26 @@ from moto.utilities.tagging_service import TaggingService
 from moto.utilities.utils import md5_hash
 
 
-def _lookup_az_id(account_id, az_name):
+def _lookup_az_id(account_id: str, az_name: str) -> Optional[str]:
     """Find the Availability zone ID given the AZ name."""
     ec2 = ec2_backends[account_id][az_name[:-1]]
     for zone in ec2.describe_availability_zones():
         if zone.name == az_name:
             return zone.zone_id
+    return None
 
 
 class AccessPoint(BaseModel):
     def __init__(
         self,
-        account_id,
-        region_name,
-        client_token,
-        file_system_id,
-        name,
-        posix_user,
-        root_directory,
-        context,
+        account_id: str,
+        region_name: str,
+        client_token: str,
+        file_system_id: str,
+        name: Optional[str],
+        posix_user: Dict[str, Any],
+        root_directory: Dict[str, str],
+        context: "EFSBackend",
     ):
         self.access_point_id = mock_random.get_random_hex(8)
         self.access_point_arn = f"arn:aws:elasticfilesystem:{region_name}:{account_id}:access-point/fsap-{self.access_point_id}"
@@ -64,7 +68,7 @@ class AccessPoint(BaseModel):
         self.root_directory = root_directory
         self.context = context
 
-    def info_json(self):
+    def info_json(self) -> Dict[str, Any]:
         tags = self.context.list_tags_for_resource(self.access_point_id)
         return {
             "ClientToken": self.client_token,
@@ -85,20 +89,18 @@ class FileSystem(CloudFormationModel):
 
     def __init__(
         self,
-        account_id,
-        region_name,
-        creation_token,
-        file_system_id,
-        context,
-        performance_mode,
-        encrypted,
-        kms_key_id,
-        throughput_mode,
-        provisioned_throughput_in_mibps,
-        availability_zone_name,
-        backup,
-        lifecycle_policies=None,
-        file_system_policy=None,
+        account_id: str,
+        region_name: str,
+        creation_token: str,
+        file_system_id: str,
+        context: "EFSBackend",
+        performance_mode: str,
+        encrypted: bool,
+        kms_key_id: str,
+        throughput_mode: str,
+        provisioned_throughput_in_mibps: int,
+        availability_zone_name: str,
+        backup: bool,
     ):
         if availability_zone_name:
             backup = True
@@ -119,8 +121,8 @@ class FileSystem(CloudFormationModel):
                 account_id, self.availability_zone_name
             )
         self._backup = backup
-        self.lifecycle_policies = lifecycle_policies or []
-        self.file_system_policy = file_system_policy
+        self.lifecycle_policies: List[Dict[str, str]] = []
+        self.file_system_policy: Optional[str] = None
 
         self._context = context
 
@@ -132,11 +134,11 @@ class FileSystem(CloudFormationModel):
 
         # Initialize some state parameters
         self.life_cycle_state = "available"
-        self._mount_targets = {}
+        self._mount_targets: Dict[str, MountTarget] = {}
         self._size_value = 0
 
     @property
-    def size_in_bytes(self):
+    def size_in_bytes(self) -> Dict[str, Any]:  # type: ignore[misc]
         return {
             "Value": self._size_value,
             "ValueInIA": 0,
@@ -145,21 +147,21 @@ class FileSystem(CloudFormationModel):
         }
 
     @property
-    def physical_resource_id(self):
+    def physical_resource_id(self) -> str:
         return self.file_system_id
 
     @property
-    def number_of_mount_targets(self):
+    def number_of_mount_targets(self) -> int:
         return len(self._mount_targets)
 
     @property
-    def backup_policy(self):
+    def backup_policy(self) -> Optional[Dict[str, str]]:
         if self._backup:
             return {"Status": "ENABLED"}
         else:
-            return
+            return None
 
-    def info_json(self):
+    def info_json(self) -> Dict[str, Any]:
         ret = {
             underscores_to_camelcase(k.capitalize()): v
             for k, v in self.__dict__.items()
@@ -180,7 +182,7 @@ class FileSystem(CloudFormationModel):
         )
         return ret
 
-    def add_mount_target(self, subnet, mount_target):
+    def add_mount_target(self, subnet: Subnet, mount_target: "MountTarget") -> None:
         # Check that the mount target doesn't violate constraints.
         for other_mount_target in self._mount_targets.values():
             if other_mount_target.subnet_vpc_id != subnet.vpc_id:
@@ -193,28 +195,33 @@ class FileSystem(CloudFormationModel):
 
         self._mount_targets[subnet.availability_zone] = mount_target
 
-    def has_mount_target(self, subnet):
+    def has_mount_target(self, subnet: Subnet) -> bool:
         return subnet.availability_zone in self._mount_targets
 
-    def iter_mount_targets(self):
+    def iter_mount_targets(self) -> Iterator["MountTarget"]:
         for mt in self._mount_targets.values():
             yield mt
 
-    def remove_mount_target(self, subnet):
+    def remove_mount_target(self, subnet: Subnet) -> None:
         del self._mount_targets[subnet.availability_zone]
 
     @staticmethod
-    def cloudformation_name_type():
-        return
+    def cloudformation_name_type() -> str:
+        return ""
 
     @staticmethod
-    def cloudformation_type():
+    def cloudformation_type() -> str:
         return "AWS::EFS::FileSystem"
 
     @classmethod
-    def create_from_cloudformation_json(
-        cls, resource_name, cloudformation_json, account_id, region_name, **kwargs
-    ):
+    def create_from_cloudformation_json(  # type: ignore[misc]
+        cls,
+        resource_name: str,
+        cloudformation_json: Any,
+        account_id: str,
+        region_name: str,
+        **kwargs: Any,
+    ) -> "FileSystem":
         # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-filesystem.html
         props = deepcopy(cloudformation_json["Properties"])
         props = {camelcase_to_underscores(k): v for k, v in props.items()}
@@ -238,29 +245,40 @@ class FileSystem(CloudFormationModel):
         )
 
     @classmethod
-    def update_from_cloudformation_json(
+    def update_from_cloudformation_json(  # type: ignore[misc]
         cls,
-        original_resource,
-        new_resource_name,
-        cloudformation_json,
-        account_id,
-        region_name,
-    ):
+        original_resource: Any,
+        new_resource_name: str,
+        cloudformation_json: Any,
+        account_id: str,
+        region_name: str,
+    ) -> None:
         raise NotImplementedError(
             "Update of EFS File System via cloudformation is not yet implemented."
         )
 
     @classmethod
-    def delete_from_cloudformation_json(
-        cls, resource_name, cloudformation_json, account_id, region_name
-    ):
-        return efs_backends[account_id][region_name].delete_file_system(resource_name)
+    def delete_from_cloudformation_json(  # type: ignore[misc]
+        cls,
+        resource_name: str,
+        cloudformation_json: Any,
+        account_id: str,
+        region_name: str,
+    ) -> None:
+        efs_backends[account_id][region_name].delete_file_system(resource_name)
 
 
 class MountTarget(CloudFormationModel):
     """A model for an EFS Mount Target."""
 
-    def __init__(self, account_id, file_system, subnet, ip_address, security_groups):
+    def __init__(
+        self,
+        account_id: str,
+        file_system: FileSystem,
+        subnet: Subnet,
+        ip_address: Optional[str],
+        security_groups: Optional[List[str]],
+    ):
         # Set the simple given parameters.
         self.file_system_id = file_system.file_system_id
         self._file_system = file_system
@@ -278,10 +296,10 @@ class MountTarget(CloudFormationModel):
 
         # Get an IP address if needed, otherwise validate the one we're given.
         if ip_address is None:
-            ip_address = subnet.get_available_subnet_ip(self)
+            ip_address = subnet.get_available_subnet_ip(self)  # type: ignore[arg-type]
         else:
             try:
-                subnet.request_ip(ip_address, self)
+                subnet.request_ip(ip_address, self)  # type: ignore[arg-type]
             except Exception as e:
                 if "IP" in str(e) and "CIDR" in str(e):
                     raise BadRequest(
@@ -295,68 +313,76 @@ class MountTarget(CloudFormationModel):
         self.owner_id = account_id
         self.mount_target_id = f"fsmt-{mock_random.get_random_hex()}"
         self.life_cycle_state = "available"
-        self.network_interface_id = None
+        self.network_interface_id: Optional[str] = None
         self.availability_zone_id = subnet.availability_zone_id
         self.availability_zone_name = subnet.availability_zone
 
-    def clean_up(self):
+    def clean_up(self) -> None:
         self._file_system.remove_mount_target(self._subnet)
         self._subnet.del_subnet_ip(self.ip_address)
 
-    def set_network_interface(self, network_interface):
+    def set_network_interface(self, network_interface: NetworkInterface) -> None:
         self.network_interface_id = network_interface.id
 
-    def info_json(self):
-        ret = {
+    def info_json(self) -> Dict[str, Any]:
+        return {
             underscores_to_camelcase(k.capitalize()): v
             for k, v in self.__dict__.items()
             if not k.startswith("_")
         }
-        return ret
 
     @property
-    def physical_resource_id(self):
-        return self.mounted_target_id
+    def physical_resource_id(self) -> str:
+        return self.mount_target_id
 
     @property
-    def subnet_vpc_id(self):
+    def subnet_vpc_id(self) -> str:
         return self._subnet.vpc_id
 
     @staticmethod
-    def cloudformation_name_type():
-        pass
+    def cloudformation_name_type() -> str:
+        return ""
 
     @staticmethod
-    def cloudformation_type():
+    def cloudformation_type() -> str:
         return "AWS::EFS::MountTarget"
 
     @classmethod
-    def create_from_cloudformation_json(
-        cls, resource_name, cloudformation_json, account_id, region_name, **kwargs
-    ):
+    def create_from_cloudformation_json(  # type: ignore[misc]
+        cls,
+        resource_name: str,
+        cloudformation_json: Any,
+        account_id: str,
+        region_name: str,
+        **kwargs: Any,
+    ) -> "MountTarget":
         # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-mounttarget.html
         props = deepcopy(cloudformation_json["Properties"])
         props = {camelcase_to_underscores(k): v for k, v in props.items()}
         return efs_backends[account_id][region_name].create_mount_target(**props)
 
     @classmethod
-    def update_from_cloudformation_json(
+    def update_from_cloudformation_json(  # type: ignore[misc]
         cls,
-        original_resource,
-        new_resource_name,
-        cloudformation_json,
-        account_id,
-        region_name,
-    ):
+        original_resource: Any,
+        new_resource_name: str,
+        cloudformation_json: Any,
+        account_id: str,
+        region_name: str,
+    ) -> None:
         raise NotImplementedError(
             "Updates of EFS Mount Target via cloudformation are not yet implemented."
         )
 
     @classmethod
-    def delete_from_cloudformation_json(
-        cls, resource_name, cloudformation_json, account_id, region_name
-    ):
-        return efs_backends[account_id][region_name].delete_mount_target(resource_name)
+    def delete_from_cloudformation_json(  # type: ignore[misc]
+        cls,
+        resource_name: str,
+        cloudformation_json: Any,
+        account_id: str,
+        region_name: str,
+    ) -> None:
+        efs_backends[account_id][region_name].delete_mount_target(resource_name)
 
 
 class EFSBackend(BaseBackend):
@@ -367,16 +393,18 @@ class EFSBackend(BaseBackend):
     such resources should always go through this class.
     """
 
-    def __init__(self, region_name, account_id):
+    def __init__(self, region_name: str, account_id: str):
         super().__init__(region_name, account_id)
-        self.creation_tokens = set()
-        self.access_points = dict()
-        self.file_systems_by_id = {}
-        self.mount_targets_by_id = {}
-        self.next_markers = {}
+        self.creation_tokens: Set[str] = set()
+        self.access_points: Dict[str, AccessPoint] = dict()
+        self.file_systems_by_id: Dict[str, FileSystem] = {}
+        self.mount_targets_by_id: Dict[str, MountTarget] = {}
+        self.next_markers: Dict[str, Union[List[MountTarget], List[FileSystem]]] = {}
         self.tagging_service = TaggingService()
 
-    def _mark_description(self, corpus, max_items):
+    def _mark_description(
+        self, corpus: Union[List[MountTarget], List[FileSystem]], max_items: int
+    ) -> Optional[str]:
         if max_items < len(corpus):
             new_corpus = corpus[max_items:]
             new_corpus_dict = [c.info_json() for c in new_corpus]
@@ -388,21 +416,21 @@ class EFSBackend(BaseBackend):
         return next_marker
 
     @property
-    def ec2_backend(self):
+    def ec2_backend(self) -> Any:  # type: ignore[misc]
         return ec2_backends[self.account_id][self.region_name]
 
     def create_file_system(
         self,
-        creation_token,
-        performance_mode,
-        encrypted,
-        kms_key_id,
-        throughput_mode,
-        provisioned_throughput_in_mibps,
-        availability_zone_name,
-        backup,
-        tags,
-    ):
+        creation_token: str,
+        performance_mode: str,
+        encrypted: bool,
+        kms_key_id: str,
+        throughput_mode: str,
+        provisioned_throughput_in_mibps: int,
+        availability_zone_name: str,
+        backup: bool,
+        tags: List[Dict[str, str]],
+    ) -> FileSystem:
         """Create a new EFS File System Volume.
 
         https://docs.aws.amazon.com/efs/latest/ug/API_CreateFileSystem.html
@@ -413,7 +441,7 @@ class EFSBackend(BaseBackend):
             raise FileSystemAlreadyExists(creation_token)
 
         # Create a new file system ID:
-        def make_id():
+        def make_id() -> str:
             return f"fs-{mock_random.get_random_hex()}"
 
         fsid = make_id()
@@ -438,13 +466,17 @@ class EFSBackend(BaseBackend):
         return self.file_systems_by_id[fsid]
 
     def describe_file_systems(
-        self, marker=None, max_items=10, creation_token=None, file_system_id=None
-    ):
+        self,
+        marker: Optional[str] = None,
+        max_items: int = 10,
+        creation_token: Optional[str] = None,
+        file_system_id: Optional[str] = None,
+    ) -> Tuple[Optional[str], List[FileSystem]]:
         """Describe all the EFS File Systems, or specific File Systems.
 
         https://docs.aws.amazon.com/efs/latest/ug/API_DescribeFileSystems.html
         """
-        # Restrict the possible corpus of resules based on inputs.
+        # Restrict the possible corpus of results based on inputs.
         if creation_token and file_system_id:
             raise BadRequest(
                 "Request cannot contain both a file system ID and a creation token."
@@ -464,7 +496,7 @@ class EFSBackend(BaseBackend):
             # Handle the case that a marker is given.
             if marker not in self.next_markers:
                 raise BadRequest("Invalid Marker")
-            corpus = self.next_markers[marker]
+            corpus = self.next_markers[marker]  # type: ignore[assignment]
         else:
             # Handle the vanilla case.
             corpus = [fs for fs in self.file_systems_by_id.values()]
@@ -475,8 +507,12 @@ class EFSBackend(BaseBackend):
         return next_marker, file_systems
 
     def create_mount_target(
-        self, file_system_id, subnet_id, ip_address=None, security_groups=None
-    ):
+        self,
+        file_system_id: str,
+        subnet_id: str,
+        ip_address: Optional[str] = None,
+        security_groups: Optional[List[str]] = None,
+    ) -> MountTarget:
         """Create a new EFS Mount Target for a given File System to a given subnet.
 
         Note that you can only create one mount target for each availability zone
@@ -516,8 +552,13 @@ class EFSBackend(BaseBackend):
         return mount_target
 
     def describe_mount_targets(
-        self, max_items, file_system_id, mount_target_id, access_point_id, marker
-    ):
+        self,
+        max_items: int,
+        file_system_id: Optional[str],
+        mount_target_id: Optional[str],
+        access_point_id: Optional[str],
+        marker: Optional[str],
+    ) -> Tuple[Optional[str], List[MountTarget]]:
         """Describe the mount targets given an access point ID, mount target ID or a file system ID.
 
         https://docs.aws.amazon.com/efs/latest/ug/API_DescribeMountTargets.html
@@ -549,7 +590,7 @@ class EFSBackend(BaseBackend):
             if marker not in self.next_markers:
                 raise BadRequest("Invalid Marker")
             corpus_mtids = {m.mount_target_id for m in corpus}
-            marked_mtids = {m.mount_target_id for m in self.next_markers[marker]}
+            marked_mtids = {m.mount_target_id for m in self.next_markers[marker]}  # type: ignore[union-attr]
             mt_ids = corpus_mtids & marked_mtids
             corpus = [self.mount_targets_by_id[mt_id] for mt_id in mt_ids]
 
@@ -558,7 +599,7 @@ class EFSBackend(BaseBackend):
         next_marker = self._mark_description(corpus, max_items)
         return next_marker, mount_targets
 
-    def delete_file_system(self, file_system_id):
+    def delete_file_system(self, file_system_id: str) -> None:
         """Delete the file system specified by the given file_system_id.
 
         Note that mount targets must be deleted first.
@@ -576,9 +617,8 @@ class EFSBackend(BaseBackend):
 
         del self.file_systems_by_id[file_system_id]
         self.creation_tokens.remove(file_system.creation_token)
-        return
 
-    def delete_mount_target(self, mount_target_id):
+    def delete_mount_target(self, mount_target_id: str) -> None:
         """Delete a mount target specified by the given mount_target_id.
 
         Note that this will also delete a network interface.
@@ -592,32 +632,39 @@ class EFSBackend(BaseBackend):
         self.ec2_backend.delete_network_interface(mount_target.network_interface_id)
         del self.mount_targets_by_id[mount_target_id]
         mount_target.clean_up()
-        return
 
-    def describe_backup_policy(self, file_system_id):
+    def describe_backup_policy(self, file_system_id: str) -> Dict[str, str]:
         backup_policy = self.file_systems_by_id[file_system_id].backup_policy
         if not backup_policy:
             raise PolicyNotFound("None")
         return backup_policy
 
-    def put_lifecycle_configuration(self, file_system_id, policies):
+    def put_lifecycle_configuration(
+        self, file_system_id: str, policies: List[Dict[str, str]]
+    ) -> None:
         _, fss = self.describe_file_systems(file_system_id=file_system_id)
         file_system = fss[0]
         file_system.lifecycle_policies = policies
 
-    def describe_lifecycle_configuration(self, file_system_id):
+    def describe_lifecycle_configuration(
+        self, file_system_id: str
+    ) -> List[Dict[str, str]]:
         _, fss = self.describe_file_systems(file_system_id=file_system_id)
         file_system = fss[0]
         return file_system.lifecycle_policies
 
-    def describe_mount_target_security_groups(self, mount_target_id):
+    def describe_mount_target_security_groups(
+        self, mount_target_id: str
+    ) -> Optional[List[str]]:
         if mount_target_id not in self.mount_targets_by_id:
             raise MountTargetNotFound(mount_target_id)
 
         mount_target = self.mount_targets_by_id[mount_target_id]
         return mount_target.security_groups
 
-    def modify_mount_target_security_groups(self, mount_target_id, security_groups):
+    def modify_mount_target_security_groups(
+        self, mount_target_id: str, security_groups: List[str]
+    ) -> None:
         if mount_target_id not in self.mount_targets_by_id:
             raise MountTargetNotFound(mount_target_id)
 
@@ -629,8 +676,13 @@ class EFSBackend(BaseBackend):
         )
 
     def create_access_point(
-        self, client_token, tags, file_system_id, posix_user, root_directory
-    ):
+        self,
+        client_token: str,
+        tags: List[Dict[str, str]],
+        file_system_id: str,
+        posix_user: Dict[str, Any],
+        root_directory: Dict[str, Any],
+    ) -> AccessPoint:
         name = next((tag["Value"] for tag in tags if tag["Key"] == "Name"), None)
         access_point = AccessPoint(
             self.account_id,
@@ -646,7 +698,7 @@ class EFSBackend(BaseBackend):
         self.access_points[access_point.access_point_id] = access_point
         return access_point
 
-    def describe_access_points(self, access_point_id):
+    def describe_access_points(self, access_point_id: str) -> List[AccessPoint]:
         """
         Pagination is not yet implemented
         """
@@ -654,18 +706,18 @@ class EFSBackend(BaseBackend):
             if access_point_id not in self.access_points:
                 raise AccessPointNotFound(access_point_id)
             return [self.access_points[access_point_id]]
-        return self.access_points.values()
+        return list(self.access_points.values())
 
-    def delete_access_point(self, access_point_id):
+    def delete_access_point(self, access_point_id: str) -> None:
         self.access_points.pop(access_point_id, None)
 
-    def list_tags_for_resource(self, resource_id):
+    def list_tags_for_resource(self, resource_id: str) -> List[Dict[str, str]]:
         return self.tagging_service.list_tags_for_resource(resource_id)["Tags"]
 
-    def tag_resource(self, resource_id, tags):
+    def tag_resource(self, resource_id: str, tags: List[Dict[str, str]]) -> None:
         self.tagging_service.tag_resource(resource_id, tags)
 
-    def untag_resource(self, resource_id, tag_keys):
+    def untag_resource(self, resource_id: str, tag_keys: List[str]) -> None:
         self.tagging_service.untag_resource_using_names(resource_id, tag_keys)
 
 
diff --git a/moto/efs/responses.py b/moto/efs/responses.py
index 156bfed35..c2b4f4412 100644
--- a/moto/efs/responses.py
+++ b/moto/efs/responses.py
@@ -1,19 +1,23 @@
 import json
+from typing import Any, Dict, Tuple, Union
 
 from moto.core.responses import BaseResponse
 
-from .models import efs_backends
+from .models import efs_backends, EFSBackend
+
+
+TYPE_RESPONSE = Tuple[str, Dict[str, Union[str, int]]]
 
 
 class EFSResponse(BaseResponse):
-    def __init__(self):
+    def __init__(self) -> None:
         super().__init__(service_name="efs")
 
     @property
-    def efs_backend(self):
+    def efs_backend(self) -> EFSBackend:
         return efs_backends[self.current_account][self.region]
 
-    def create_file_system(self):
+    def create_file_system(self) -> TYPE_RESPONSE:
         creation_token = self._get_param("CreationToken")
         performance_mode = self._get_param("PerformanceMode")
         encrypted = self._get_param("Encrypted")
@@ -41,7 +45,7 @@ class EFSResponse(BaseResponse):
             {"status": 201, "Content-Type": "application/json"},
         )
 
-    def describe_file_systems(self):
+    def describe_file_systems(self) -> TYPE_RESPONSE:
         max_items = self._get_int_param("MaxItems", 10)
         marker = self._get_param("Marker")
         creation_token = self._get_param("CreationToken")
@@ -52,14 +56,16 @@ class EFSResponse(BaseResponse):
             creation_token=creation_token,
             file_system_id=file_system_id,
         )
-        resp_json = {"FileSystems": [fs.info_json() for fs in file_systems]}
+        resp_json: Dict[str, Any] = {
+            "FileSystems": [fs.info_json() for fs in file_systems]
+        }
         if marker:
             resp_json["Marker"] = marker
         if next_marker:
             resp_json["NextMarker"] = next_marker
         return json.dumps(resp_json), {"Content-Type": "application/json"}
 
-    def create_mount_target(self):
+    def create_mount_target(self) -> TYPE_RESPONSE:
         file_system_id = self._get_param("FileSystemId")
         subnet_id = self._get_param("SubnetId")
         ip_address = self._get_param("IpAddress")
@@ -75,7 +81,7 @@ class EFSResponse(BaseResponse):
             {"Content-Type": "application/json"},
         )
 
-    def describe_mount_targets(self):
+    def describe_mount_targets(self) -> TYPE_RESPONSE:
         max_items = self._get_int_param("MaxItems", 10)
         marker = self._get_param("Marker")
         file_system_id = self._get_param("FileSystemId")
@@ -88,30 +94,32 @@ class EFSResponse(BaseResponse):
             access_point_id=access_point_id,
             marker=marker,
         )
-        resp_json = {"MountTargets": [mt.info_json() for mt in mount_targets]}
+        resp_json: Dict[str, Any] = {
+            "MountTargets": [mt.info_json() for mt in mount_targets]
+        }
         if marker:
             resp_json["Marker"] = marker
         if next_marker:
             resp_json["NextMarker"] = next_marker
         return json.dumps(resp_json), {"Content-Type": "application/json"}
 
-    def delete_file_system(self):
+    def delete_file_system(self) -> TYPE_RESPONSE:
         file_system_id = self._get_param("FileSystemId")
         self.efs_backend.delete_file_system(file_system_id)
         return json.dumps(dict()), {"status": 204, "Content-Type": "application/json"}
 
-    def delete_mount_target(self):
+    def delete_mount_target(self) -> TYPE_RESPONSE:
         mount_target_id = self._get_param("MountTargetId")
         self.efs_backend.delete_mount_target(mount_target_id)
         return json.dumps(dict()), {"status": 204, "Content-Type": "application/json"}
 
-    def describe_backup_policy(self):
+    def describe_backup_policy(self) -> TYPE_RESPONSE:
         file_system_id = self._get_param("FileSystemId")
         backup_policy = self.efs_backend.describe_backup_policy(file_system_id)
         resp = {"BackupPolicy": backup_policy}
         return json.dumps(resp), {"Content-Type": "application/json"}
 
-    def put_lifecycle_configuration(self):
+    def put_lifecycle_configuration(self) -> TYPE_RESPONSE:
         file_system_id = self._get_param("FileSystemId")
         policies = self._get_param("LifecyclePolicies")
         self.efs_backend.put_lifecycle_configuration(file_system_id, policies)
@@ -119,14 +127,14 @@ class EFSResponse(BaseResponse):
             "Content-Type": "application/json"
         }
 
-    def describe_lifecycle_configuration(self):
+    def describe_lifecycle_configuration(self) -> TYPE_RESPONSE:
         file_system_id = self._get_param("FileSystemId")
         policies = self.efs_backend.describe_lifecycle_configuration(file_system_id)
         return json.dumps({"LifecyclePolicies": policies}), {
             "Content-Type": "application/json"
         }
 
-    def describe_mount_target_security_groups(self):
+    def describe_mount_target_security_groups(self) -> TYPE_RESPONSE:
         mount_target_id = self._get_param("MountTargetId")
         security_groups = self.efs_backend.describe_mount_target_security_groups(
             mount_target_id
@@ -135,7 +143,7 @@ class EFSResponse(BaseResponse):
             "Content-Type": "application/json"
         }
 
-    def modify_mount_target_security_groups(self):
+    def modify_mount_target_security_groups(self) -> TYPE_RESPONSE:
         mount_target_id = self._get_param("MountTargetId")
         security_groups = self._get_param("SecurityGroups")
         self.efs_backend.modify_mount_target_security_groups(
@@ -143,7 +151,7 @@ class EFSResponse(BaseResponse):
         )
         return "{}", {"Content-Type": "application/json"}
 
-    def create_access_point(self):
+    def create_access_point(self) -> TYPE_RESPONSE:
         client_token = self._get_param("ClientToken")
         tags = self._get_param("Tags") or []
         file_system_id = self._get_param("FileSystemId")
@@ -160,29 +168,29 @@ class EFSResponse(BaseResponse):
             "Content-Type": "application/json"
         }
 
-    def describe_access_points(self):
+    def describe_access_points(self) -> TYPE_RESPONSE:
         access_point_id = self._get_param("AccessPointId")
         access_points = self.efs_backend.describe_access_points(access_point_id)
         resp = [ap.info_json() for ap in access_points]
         return json.dumps({"AccessPoints": resp}), {"Content-Type": "application/json"}
 
-    def delete_access_point(self):
+    def delete_access_point(self) -> TYPE_RESPONSE:
         access_point_id = self._get_param("AccessPointId")
         self.efs_backend.delete_access_point(access_point_id)
         return "{}", {"Content-Type": "application/json"}
 
-    def list_tags_for_resource(self):
+    def list_tags_for_resource(self) -> TYPE_RESPONSE:
         resource_id = self._get_param("ResourceId")
         tags = self.efs_backend.list_tags_for_resource(resource_id)
         return json.dumps({"Tags": tags}), {"Content-Type": "application/json"}
 
-    def tag_resource(self):
+    def tag_resource(self) -> TYPE_RESPONSE:
         resource_id = self._get_param("ResourceId")
         tags = self._get_param("Tags")
         self.efs_backend.tag_resource(resource_id, tags)
         return "{}", {"Content-Type": "application/json"}
 
-    def untag_resource(self):
+    def untag_resource(self) -> TYPE_RESPONSE:
         resource_id = self._get_param("ResourceId")
         tag_keys = self.querystring.get("tagKeys", [])
         self.efs_backend.untag_resource(resource_id, tag_keys)
diff --git a/moto/eks/exceptions.py b/moto/eks/exceptions.py
index f25a5fcd6..61ae17c3b 100644
--- a/moto/eks/exceptions.py
+++ b/moto/eks/exceptions.py
@@ -1,16 +1,17 @@
 import json
+from typing import Any, Dict, Tuple
 
 from moto.core.exceptions import AWSError
 
 
 class EKSError(AWSError):
-    def __init__(self, **kwargs):
-        super(AWSError, self).__init__(error_type=self.TYPE, message="")
+    def __init__(self, **kwargs: Any):
+        super(AWSError, self).__init__(error_type=self.TYPE, message="")  # type: ignore
         self.description = json.dumps(kwargs)
         self.headers = {"status": self.STATUS, "x-amzn-ErrorType": self.TYPE}
         self.code = self.STATUS
 
-    def response(self):
+    def response(self) -> Tuple[int, Dict[str, Any], str]:  # type: ignore[override]
         return self.STATUS, self.headers, self.description
 
 
diff --git a/moto/eks/models.py b/moto/eks/models.py
index 30247c069..74df856df 100644
--- a/moto/eks/models.py
+++ b/moto/eks/models.py
@@ -1,4 +1,5 @@
 from datetime import datetime
+from typing import Any, Dict, List, Optional, Tuple, Iterator
 
 from moto.core import BaseBackend, BackendDict
 from moto.core.utils import iso_8601_datetime_without_milliseconds
@@ -52,7 +53,7 @@ DEFAULT_AMI_TYPE = "AL2_x86_64"
 DEFAULT_CAPACITY_TYPE = "ON_DEMAND"
 DEFAULT_DISK_SIZE = "20"
 DEFAULT_INSTANCE_TYPES = ["t3.medium"]
-DEFAULT_NODEGROUP_HEALTH = {"issues": []}
+DEFAULT_NODEGROUP_HEALTH: Dict[str, Any] = {"issues": []}
 DEFAULT_RELEASE_VERSION = "1.19.8-20210414"
 DEFAULT_REMOTE_ACCESS = {"ec2SshKey": "eksKeypair"}
 DEFAULT_SCALING_CONFIG = {"minSize": 2, "maxSize": 2, "desiredSize": 2}
@@ -91,28 +92,28 @@ NODEGROUP_NOT_FOUND_MSG = "No node group found for name: {nodegroupName}."
 class Cluster:
     def __init__(
         self,
-        name,
-        role_arn,
-        resources_vpc_config,
-        account_id,
-        region_name,
-        aws_partition,
-        version=None,
-        kubernetes_network_config=None,
-        logging=None,
-        client_request_token=None,
-        tags=None,
-        encryption_config=None,
+        name: str,
+        role_arn: str,
+        resources_vpc_config: Dict[str, Any],
+        account_id: str,
+        region_name: str,
+        aws_partition: str,
+        version: Optional[str] = None,
+        kubernetes_network_config: Optional[Dict[str, str]] = None,
+        logging: Optional[Dict[str, Any]] = None,
+        client_request_token: Optional[str] = None,
+        tags: Optional[Dict[str, str]] = None,
+        encryption_config: Optional[List[Dict[str, Any]]] = None,
     ):
         if encryption_config is None:
             encryption_config = []
         if tags is None:
             tags = dict()
 
-        self.nodegroups = dict()
+        self.nodegroups: Dict[str, ManagedNodegroup] = dict()
         self.nodegroup_count = 0
 
-        self.fargate_profiles = dict()
+        self.fargate_profiles: Dict[str, FargateProfile] = dict()
         self.fargate_profile_count = 0
 
         self.arn = CLUSTER_ARN_TEMPLATE.format(
@@ -141,7 +142,7 @@ class Cluster:
         self.role_arn = role_arn
         self.tags = tags
 
-    def __iter__(self):
+    def __iter__(self) -> Iterator[Tuple[str, Any]]:
         yield "name", self.name
         yield "arn", self.arn
         yield "createdAt", self.creation_date
@@ -159,23 +160,23 @@ class Cluster:
         yield "tags", self.tags
         yield "encryptionConfig", self.encryption_config
 
-    def isActive(self):
+    def isActive(self) -> bool:
         return self.status == "ACTIVE"
 
 
 class FargateProfile:
     def __init__(
         self,
-        cluster_name,
-        fargate_profile_name,
-        pod_execution_role_arn,
-        selectors,
-        account_id,
-        region_name,
-        aws_partition,
-        client_request_token=None,
-        subnets=None,
-        tags=None,
+        cluster_name: str,
+        fargate_profile_name: str,
+        pod_execution_role_arn: str,
+        selectors: List[Dict[str, Any]],
+        account_id: str,
+        region_name: str,
+        aws_partition: str,
+        client_request_token: Optional[str] = None,
+        subnets: Optional[List[str]] = None,
+        tags: Optional[Dict[str, str]] = None,
     ):
         if subnets is None:
             subnets = list()
@@ -202,7 +203,7 @@ class FargateProfile:
         self.subnets = subnets
         self.tags = tags
 
-    def __iter__(self):
+    def __iter__(self) -> Iterator[Tuple[str, Any]]:
         yield "clusterName", self.cluster_name
         yield "createdAt", self.created_at
         yield "fargateProfileArn", self.fargate_profile_arn
@@ -217,33 +218,33 @@ class FargateProfile:
 class ManagedNodegroup:
     def __init__(
         self,
-        cluster_name,
-        node_role,
-        nodegroup_name,
-        subnets,
-        account_id,
-        region_name,
-        aws_partition,
-        scaling_config=None,
-        disk_size=None,
-        instance_types=None,
-        ami_type=None,
-        remote_access=None,
-        labels=None,
-        taints=None,
-        tags=None,
-        client_request_token=None,
-        launch_template=None,
-        capacity_type=None,
-        version=None,
-        release_version=None,
+        cluster_name: str,
+        node_role: str,
+        nodegroup_name: str,
+        subnets: List[str],
+        account_id: str,
+        region_name: str,
+        aws_partition: str,
+        scaling_config: Optional[Dict[str, int]] = None,
+        disk_size: Optional[int] = None,
+        instance_types: Optional[List[str]] = None,
+        ami_type: Optional[str] = None,
+        remote_access: Optional[Dict[str, Any]] = None,
+        labels: Optional[Dict[str, str]] = None,
+        taints: Optional[List[Dict[str, str]]] = None,
+        tags: Optional[Dict[str, str]] = None,
+        client_request_token: Optional[str] = None,
+        launch_template: Optional[Dict[str, str]] = None,
+        capacity_type: Optional[str] = None,
+        version: Optional[str] = None,
+        release_version: Optional[str] = None,
     ):
         if tags is None:
             tags = dict()
         if labels is None:
             labels = dict()
         if taints is None:
-            taints = dict()
+            taints = []
 
         self.uuid = str(random.uuid4())
         self.arn = NODEGROUP_ARN_TEMPLATE.format(
@@ -291,19 +292,19 @@ class ManagedNodegroup:
             ec2 = ec2_backends[account_id][region_name]
 
             template = None
-            if "name" in self.launch_template:
-                name = self.launch_template["name"]
+            if "name" in self.launch_template:  # type: ignore
+                name = self.launch_template["name"]  # type: ignore
                 template = ec2.describe_launch_templates(template_names=[name])[0]
-            elif "id" in self.launch_template:
-                _id = self.launch_template["id"]
+            elif "id" in self.launch_template:  # type: ignore
+                _id = self.launch_template["id"]  # type: ignore
                 template = ec2.describe_launch_templates(template_ids=[_id])[0]
 
-            self.launch_template["id"] = template.id
-            self.launch_template["name"] = template.name
+            self.launch_template["id"] = template.id  # type: ignore
+            self.launch_template["name"] = template.name  # type: ignore
         except:  # noqa: E722 Do not use bare except
             pass
 
-    def __iter__(self):
+    def __iter__(self) -> Iterator[Tuple[str, Any]]:
         yield "nodegroupName", self.nodegroup_name
         yield "nodegroupArn", self.arn
         yield "clusterName", self.cluster_name
@@ -329,24 +330,24 @@ class ManagedNodegroup:
 
 
 class EKSBackend(BaseBackend):
-    def __init__(self, region_name, account_id):
+    def __init__(self, region_name: str, account_id: str):
         super().__init__(region_name, account_id)
-        self.clusters = dict()
+        self.clusters: Dict[str, Cluster] = dict()
         self.cluster_count = 0
         self.partition = get_partition(region_name)
 
     def create_cluster(
         self,
-        name,
-        role_arn,
-        resources_vpc_config,
-        version=None,
-        kubernetes_network_config=None,
-        logging=None,
-        client_request_token=None,
-        tags=None,
-        encryption_config=None,
-    ):
+        name: str,
+        role_arn: str,
+        resources_vpc_config: Dict[str, Any],
+        version: Optional[str] = None,
+        kubernetes_network_config: Optional[Dict[str, str]] = None,
+        logging: Optional[Dict[str, Any]] = None,
+        client_request_token: Optional[str] = None,
+        tags: Optional[Dict[str, str]] = None,
+        encryption_config: Optional[List[Dict[str, Any]]] = None,
+    ) -> Cluster:
         if name in self.clusters:
             # Cluster exists.
             raise ResourceInUseException(
@@ -377,14 +378,14 @@ class EKSBackend(BaseBackend):
 
     def create_fargate_profile(
         self,
-        fargate_profile_name,
-        cluster_name,
-        selectors,
-        pod_execution_role_arn,
-        subnets=None,
-        client_request_token=None,
-        tags=None,
-    ):
+        fargate_profile_name: str,
+        cluster_name: str,
+        selectors: List[Dict[str, Any]],
+        pod_execution_role_arn: str,
+        subnets: Optional[List[str]] = None,
+        client_request_token: Optional[str] = None,
+        tags: Optional[Dict[str, str]] = None,
+    ) -> FargateProfile:
         try:
             # Cluster exists.
             cluster = self.clusters[cluster_name]
@@ -431,24 +432,24 @@ class EKSBackend(BaseBackend):
 
     def create_nodegroup(
         self,
-        cluster_name,
-        node_role,
-        nodegroup_name,
-        subnets,
-        scaling_config=None,
-        disk_size=None,
-        instance_types=None,
-        ami_type=None,
-        remote_access=None,
-        labels=None,
-        taints=None,
-        tags=None,
-        client_request_token=None,
-        launch_template=None,
-        capacity_type=None,
-        version=None,
-        release_version=None,
-    ):
+        cluster_name: str,
+        node_role: str,
+        nodegroup_name: str,
+        subnets: List[str],
+        scaling_config: Optional[Dict[str, int]] = None,
+        disk_size: Optional[int] = None,
+        instance_types: Optional[List[str]] = None,
+        ami_type: Optional[str] = None,
+        remote_access: Optional[Dict[str, Any]] = None,
+        labels: Optional[Dict[str, str]] = None,
+        taints: Optional[List[Dict[str, str]]] = None,
+        tags: Optional[Dict[str, str]] = None,
+        client_request_token: Optional[str] = None,
+        launch_template: Optional[Dict[str, str]] = None,
+        capacity_type: Optional[str] = None,
+        version: Optional[str] = None,
+        release_version: Optional[str] = None,
+    ) -> ManagedNodegroup:
         try:
             # Cluster exists.
             cluster = self.clusters[cluster_name]
@@ -506,7 +507,7 @@ class EKSBackend(BaseBackend):
         cluster.nodegroup_count += 1
         return nodegroup
 
-    def describe_cluster(self, name):
+    def describe_cluster(self, name: str) -> Cluster:
         try:
             # Cluster exists.
             return self.clusters[name]
@@ -520,7 +521,9 @@ class EKSBackend(BaseBackend):
                 message=CLUSTER_NOT_FOUND_MSG.format(clusterName=name),
             )
 
-    def describe_fargate_profile(self, cluster_name, fargate_profile_name):
+    def describe_fargate_profile(
+        self, cluster_name: str, fargate_profile_name: str
+    ) -> FargateProfile:
         try:
             # Cluster exists.
             cluster = self.clusters[cluster_name]
@@ -548,7 +551,9 @@ class EKSBackend(BaseBackend):
                 ),
             )
 
-    def describe_nodegroup(self, cluster_name, nodegroup_name):
+    def describe_nodegroup(
+        self, cluster_name: str, nodegroup_name: str
+    ) -> ManagedNodegroup:
         try:
             # Cluster exists.
             cluster = self.clusters[cluster_name]
@@ -574,7 +579,7 @@ class EKSBackend(BaseBackend):
                 message=NODEGROUP_NOT_FOUND_MSG.format(nodegroupName=nodegroup_name),
             )
 
-    def delete_cluster(self, name):
+    def delete_cluster(self, name: str) -> Cluster:
         try:
             # Cluster exists.
             validate_safe_to_delete(self.clusters[name])
@@ -592,7 +597,9 @@ class EKSBackend(BaseBackend):
         self.cluster_count -= 1
         return result
 
-    def delete_fargate_profile(self, cluster_name, fargate_profile_name):
+    def delete_fargate_profile(
+        self, cluster_name: str, fargate_profile_name: str
+    ) -> FargateProfile:
         try:
             # Cluster exists.
             cluster = self.clusters[cluster_name]
@@ -623,7 +630,9 @@ class EKSBackend(BaseBackend):
         cluster.fargate_profile_count -= 1
         return deleted_fargate_profile
 
-    def delete_nodegroup(self, cluster_name, nodegroup_name):
+    def delete_nodegroup(
+        self, cluster_name: str, nodegroup_name: str
+    ) -> ManagedNodegroup:
         try:
             # Cluster exists.
             cluster = self.clusters[cluster_name]
@@ -652,7 +661,7 @@ class EKSBackend(BaseBackend):
         cluster.nodegroup_count -= 1
         return result
 
-    def tag_resource(self, resource_arn, tags):
+    def tag_resource(self, resource_arn: str, tags: Dict[str, str]) -> None:
         """
         This function currently will tag an EKS cluster only.  It does not tag a managed node group
         """
@@ -673,9 +682,8 @@ class EKSBackend(BaseBackend):
                 message="An error occurred (NotFoundException) when calling the TagResource operation: Resource was not found",
             )
         cluster.tags.update(tags)
-        return ""
 
-    def untag_resource(self, resource_arn, tag_keys):
+    def untag_resource(self, resource_arn: str, tag_keys: List[str]) -> None:
         """
         This function currently will remove tags on an EKS cluster only.  It does not remove tags from a managed node group
         """
@@ -700,9 +708,8 @@ class EKSBackend(BaseBackend):
         for name in tag_keys:
             if name in cluster.tags:
                 del cluster.tags[name]
-        return ""
 
-    def list_tags_for_resource(self, resource_arn):
+    def list_tags_for_resource(self, resource_arn: str) -> Dict[str, str]:
         """
         This function currently will list tags on an EKS cluster only.  It does not list tags from a managed node group
         """
@@ -724,19 +731,29 @@ class EKSBackend(BaseBackend):
             )
         return cluster.tags
 
-    def list_clusters(self, max_results, next_token):
-        return paginated_list(self.clusters.keys(), max_results, next_token)
+    def list_clusters(
+        self, max_results: int, next_token: Optional[str]
+    ) -> Tuple[List[Cluster], Optional[Cluster]]:
+        return paginated_list(list(self.clusters.keys()), max_results, next_token)
 
-    def list_fargate_profiles(self, cluster_name, max_results, next_token):
+    def list_fargate_profiles(
+        self, cluster_name: str, max_results: int, next_token: Optional[str]
+    ) -> Tuple[List[FargateProfile], Optional[FargateProfile]]:
         cluster = self.clusters[cluster_name]
-        return paginated_list(cluster.fargate_profiles.keys(), max_results, next_token)
+        return paginated_list(
+            list(cluster.fargate_profiles.keys()), max_results, next_token
+        )
 
-    def list_nodegroups(self, cluster_name, max_results, next_token):
+    def list_nodegroups(
+        self, cluster_name: str, max_results: int, next_token: Optional[str]
+    ) -> Tuple[List[ManagedNodegroup], Optional[ManagedNodegroup]]:
         cluster = self.clusters[cluster_name]
-        return paginated_list(cluster.nodegroups.keys(), max_results, next_token)
+        return paginated_list(list(cluster.nodegroups.keys()), max_results, next_token)
 
 
-def paginated_list(full_list, max_results, next_token):
+def paginated_list(
+    full_list: List[Any], max_results: int, next_token: Optional[str]
+) -> Tuple[List[Any], Optional[Any]]:
     """
     Returns a tuple containing a slice of the full list
     starting at next_token and ending with at most the
@@ -754,7 +771,7 @@ def paginated_list(full_list, max_results, next_token):
     return sorted_list[start:end], new_next
 
 
-def validate_safe_to_delete(cluster):
+def validate_safe_to_delete(cluster: Cluster) -> None:
     # A cluster which has nodegroups attached can not be deleted.
     if cluster.nodegroup_count:
         nodegroup_names = ",".join(list(cluster.nodegroups.keys()))
@@ -766,7 +783,9 @@ def validate_safe_to_delete(cluster):
         )
 
 
-def validate_launch_template_combination(disk_size, remote_access):
+def validate_launch_template_combination(
+    disk_size: Optional[int], remote_access: Optional[Dict[str, Any]]
+) -> None:
     if not (disk_size or remote_access):
         return
 
@@ -777,8 +796,8 @@ def validate_launch_template_combination(disk_size, remote_access):
     )
 
 
-def _validate_fargate_profile_selectors(selectors):
-    def raise_exception(message):
+def _validate_fargate_profile_selectors(selectors: List[Dict[str, Any]]) -> None:
+    def raise_exception(message: str) -> None:
         raise InvalidParameterException(
             clusterName=None,
             nodegroupName=None,
diff --git a/moto/eks/responses.py b/moto/eks/responses.py
index c0deb4845..b87054eab 100644
--- a/moto/eks/responses.py
+++ b/moto/eks/responses.py
@@ -1,22 +1,24 @@
 import json
+from typing import Any
 from urllib.parse import unquote
+from moto.core.common_types import TYPE_RESPONSE
 from moto.core.responses import BaseResponse
 
-from .models import eks_backends
+from .models import eks_backends, EKSBackend
 
 DEFAULT_MAX_RESULTS = 100
 DEFAULT_NEXT_TOKEN = ""
 
 
 class EKSResponse(BaseResponse):
-    def __init__(self):
+    def __init__(self) -> None:
         super().__init__(service_name="eks")
 
     @property
-    def eks_backend(self):
+    def eks_backend(self) -> EKSBackend:
         return eks_backends[self.current_account][self.region]
 
-    def create_cluster(self):
+    def create_cluster(self) -> TYPE_RESPONSE:
         name = self._get_param("name")
         version = self._get_param("version")
         role_arn = self._get_param("roleArn")
@@ -41,7 +43,7 @@ class EKSResponse(BaseResponse):
 
         return 200, {}, json.dumps({"cluster": dict(cluster)})
 
-    def create_fargate_profile(self):
+    def create_fargate_profile(self) -> TYPE_RESPONSE:
         fargate_profile_name = self._get_param("fargateProfileName")
         cluster_name = self._get_param("name")
         pod_execution_role_arn = self._get_param("podExecutionRoleArn")
@@ -62,7 +64,7 @@ class EKSResponse(BaseResponse):
 
         return 200, {}, json.dumps({"fargateProfile": dict(fargate_profile)})
 
-    def create_nodegroup(self):
+    def create_nodegroup(self) -> TYPE_RESPONSE:
         cluster_name = self._get_param("name")
         nodegroup_name = self._get_param("nodegroupName")
         scaling_config = self._get_param("scalingConfig")
@@ -101,14 +103,14 @@ class EKSResponse(BaseResponse):
 
         return 200, {}, json.dumps({"nodegroup": dict(nodegroup)})
 
-    def describe_cluster(self):
+    def describe_cluster(self) -> TYPE_RESPONSE:
         name = self._get_param("name")
 
         cluster = self.eks_backend.describe_cluster(name=name)
 
         return 200, {}, json.dumps({"cluster": dict(cluster)})
 
-    def describe_fargate_profile(self):
+    def describe_fargate_profile(self) -> TYPE_RESPONSE:
         cluster_name = self._get_param("name")
         fargate_profile_name = self._get_param("fargateProfileName")
 
@@ -117,7 +119,7 @@ class EKSResponse(BaseResponse):
         )
         return 200, {}, json.dumps({"fargateProfile": dict(fargate_profile)})
 
-    def describe_nodegroup(self):
+    def describe_nodegroup(self) -> TYPE_RESPONSE:
         cluster_name = self._get_param("name")
         nodegroup_name = self._get_param("nodegroupName")
 
@@ -127,7 +129,7 @@ class EKSResponse(BaseResponse):
 
         return 200, {}, json.dumps({"nodegroup": dict(nodegroup)})
 
-    def list_clusters(self):
+    def list_clusters(self) -> TYPE_RESPONSE:
         max_results = self._get_int_param("maxResults", DEFAULT_MAX_RESULTS)
         next_token = self._get_param("nextToken", DEFAULT_NEXT_TOKEN)
 
@@ -137,7 +139,7 @@ class EKSResponse(BaseResponse):
 
         return 200, {}, json.dumps(dict(clusters=clusters, nextToken=next_token))
 
-    def list_fargate_profiles(self):
+    def list_fargate_profiles(self) -> TYPE_RESPONSE:
         cluster_name = self._get_param("name")
         max_results = self._get_int_param("maxResults", DEFAULT_MAX_RESULTS)
         next_token = self._get_param("nextToken", DEFAULT_NEXT_TOKEN)
@@ -154,7 +156,7 @@ class EKSResponse(BaseResponse):
             ),
         )
 
-    def list_nodegroups(self):
+    def list_nodegroups(self) -> TYPE_RESPONSE:
         cluster_name = self._get_param("name")
         max_results = self._get_int_param("maxResults", DEFAULT_MAX_RESULTS)
         next_token = self._get_param("nextToken", DEFAULT_NEXT_TOKEN)
@@ -165,14 +167,14 @@ class EKSResponse(BaseResponse):
 
         return 200, {}, json.dumps(dict(nodegroups=nodegroups, nextToken=next_token))
 
-    def delete_cluster(self):
+    def delete_cluster(self) -> TYPE_RESPONSE:
         name = self._get_param("name")
 
         cluster = self.eks_backend.delete_cluster(name=name)
 
         return 200, {}, json.dumps({"cluster": dict(cluster)})
 
-    def delete_fargate_profile(self):
+    def delete_fargate_profile(self) -> TYPE_RESPONSE:
         cluster_name = self._get_param("name")
         fargate_profile_name = self._get_param("fargateProfileName")
 
@@ -182,7 +184,7 @@ class EKSResponse(BaseResponse):
 
         return 200, {}, json.dumps({"fargateProfile": dict(fargate_profile)})
 
-    def delete_nodegroup(self):
+    def delete_nodegroup(self) -> TYPE_RESPONSE:
         cluster_name = self._get_param("name")
         nodegroup_name = self._get_param("nodegroupName")
 
@@ -192,7 +194,7 @@ class EKSResponse(BaseResponse):
 
         return 200, {}, json.dumps({"nodegroup": dict(nodegroup)})
 
-    def tags(self, request, full_url, headers):
+    def tags(self, request: Any, full_url: str, headers: Any) -> TYPE_RESPONSE:  # type: ignore[return]
         self.setup_class(request, full_url, headers)
         if request.method == "GET":
             return self.list_tags_for_resource()
@@ -201,25 +203,25 @@ class EKSResponse(BaseResponse):
         if request.method == "DELETE":
             return self.untag_resource()
 
-    def tag_resource(self):
+    def tag_resource(self) -> TYPE_RESPONSE:
         self.eks_backend.tag_resource(
             self._extract_arn_from_path(), self._get_param("tags")
         )
 
         return 200, {}, ""
 
-    def untag_resource(self):
+    def untag_resource(self) -> TYPE_RESPONSE:
         self.eks_backend.untag_resource(
             self._extract_arn_from_path(), self._get_param("tagKeys")
         )
 
         return 200, {}, ""
 
-    def list_tags_for_resource(self):
+    def list_tags_for_resource(self) -> TYPE_RESPONSE:
         tags = self.eks_backend.list_tags_for_resource(self._extract_arn_from_path())
         return 200, {}, json.dumps({"tags": tags})
 
-    def _extract_arn_from_path(self):
+    def _extract_arn_from_path(self) -> str:
         # /tags/arn_that_may_contain_a_slash
         path = unquote(self.path)
         return "/".join(path.split("/")[2:])
diff --git a/moto/eks/utils.py b/moto/eks/utils.py
index 686cd2aad..d7722dbc7 100644
--- a/moto/eks/utils.py
+++ b/moto/eks/utils.py
@@ -6,7 +6,7 @@ from boto3 import Session
 from moto.eks.exceptions import InvalidParameterException
 
 
-def get_partition(region):
+def get_partition(region: str) -> str:
     valid_matches = [
         # (region prefix, aws partition)
         ("cn-", "aws-cn"),
@@ -21,7 +21,7 @@ def get_partition(region):
     return "aws"
 
 
-def method_name(use_parent=False):
+def method_name(use_parent: bool = False) -> str:
     """
     Returns the name of the method which called it from the stack in PascalCase.
     If `use_parent` is True, returns the parent of the method which called it instead.
@@ -37,12 +37,12 @@ def method_name(use_parent=False):
     )
 
 
-def validate_role_arn(arn):
+def validate_role_arn(arn: str) -> None:
     valid_role_arn_format = re.compile(
         "arn:(?P<partition>.+):iam::(?P<account_id>[0-9]{12}):role/.+"
     )
     match = valid_role_arn_format.match(arn)
-    valid_partition = match.group("partition") in Session().get_available_partitions()
+    valid_partition = match.group("partition") in Session().get_available_partitions()  # type: ignore
 
     if not all({arn, match, valid_partition}):
-        raise InvalidParameterException("Invalid Role Arn: '" + arn + "'")
+        raise InvalidParameterException("Invalid Role Arn: '" + arn + "'")  # type: ignore
diff --git a/moto/kms/models.py b/moto/kms/models.py
index 8549da5ea..917407699 100644
--- a/moto/kms/models.py
+++ b/moto/kms/models.py
@@ -363,7 +363,7 @@ class KmsBackend(BaseBackend):
         key_id = self.get_alias_name(key_id)
         key_id = self.get_key_id(key_id)
         if key_id.startswith("alias/"):
-            key_id = self.get_key_id_from_alias(key_id)
+            key_id = self.get_key_id(self.get_key_id_from_alias(key_id))
         return key_id
 
     def alias_exists(self, alias_name):
diff --git a/moto/rds/models.py b/moto/rds/models.py
index d394f933e..77124b0c4 100644
--- a/moto/rds/models.py
+++ b/moto/rds/models.py
@@ -1677,6 +1677,10 @@ class RDSBackend(BaseBackend):
         #     "OptionGroupArn": "arn:aws:rds:us-east-1:{account}:og:default:postgres-10"
         # }
         # The CLI does not allow deletion of default groups
+
+        # add region and account-id to construct the arn
+        option_group_kwargs["region"] = self.region_name
+        option_group_kwargs["account_id"] = self.account_id
         option_group = OptionGroup(**option_group_kwargs)
         self.option_groups[option_group_id] = option_group
         return option_group
@@ -2209,7 +2213,15 @@ class RDSBackend(BaseBackend):
 
 
 class OptionGroup(object):
-    def __init__(self, name, engine_name, major_engine_version, description=None):
+    def __init__(
+        self,
+        name,
+        engine_name,
+        major_engine_version,
+        region,
+        account_id,
+        description=None,
+    ):
         self.engine_name = engine_name
         self.major_engine_version = major_engine_version
         self.description = description
@@ -2218,6 +2230,7 @@ class OptionGroup(object):
         self.options = {}
         self.vpcId = "null"
         self.tags = []
+        self.arn = f"arn:aws:rds:{region}:{account_id}:og:{name}"
 
     def to_json(self):
         template = Template(
@@ -2228,7 +2241,8 @@ class OptionGroup(object):
     "AllowsVpcAndNonVpcInstanceMemberships": "{{ option_group.vpc_and_non_vpc_instance_memberships }}",
     "EngineName": "{{ option_group.engine_name }}",
     "Options": [],
-    "OptionGroupName": "{{ option_group.name }}"
+    "OptionGroupName": "{{ option_group.name }},
+    "OptionGroupArn": "{{ option_group.arn }}
 }"""
         )
         return template.render(option_group=self)
@@ -2241,6 +2255,7 @@ class OptionGroup(object):
           <MajorEngineVersion>{{ option_group.major_engine_version }}</MajorEngineVersion>
           <EngineName>{{ option_group.engine_name }}</EngineName>
           <OptionGroupDescription>{{ option_group.description }}</OptionGroupDescription>
+          <OptionGroupArn>{{ option_group.arn }}</OptionGroupArn>
           <Options/>
         </OptionGroup>"""
         )
diff --git a/setup.cfg b/setup.cfg
index 741d0ddf1..228066350 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -229,7 +229,7 @@ disable = W,C,R,E
 enable = anomalous-backslash-in-string, arguments-renamed, dangerous-default-value, deprecated-module, function-redefined, import-self, redefined-builtin, redefined-outer-name, reimported, pointless-statement, super-with-arguments, unused-argument, unused-import, unused-variable, useless-else-on-loop, wildcard-import
 
 [mypy]
-files= moto/a*,moto/b*,moto/c*,moto/d*,moto/ebs/,moto/ec2,moto/ec2instanceconnect,moto/ecr,moto/ecs,moto/es,moto/moto_api
+files= moto/a*,moto/b*,moto/c*,moto/d*,moto/ebs/,moto/ec2,moto/ec2instanceconnect,moto/ecr,moto/ecs,moto/efs,moto/eks,moto/es,moto/moto_api
 show_column_numbers=True
 show_error_codes = True
 disable_error_code=abstract


Test patch:
diff --git a/tests/test_apigateway/test_apigateway.py b/tests/test_apigateway/test_apigateway.py
index 60b409499..911850a90 100644
--- a/tests/test_apigateway/test_apigateway.py
+++ b/tests/test_apigateway/test_apigateway.py
@@ -52,6 +52,12 @@ def test_update_rest_api():
         {"op": "replace", "path": "/apiKeySource", "value": "AUTHORIZER"},
         {"op": "replace", "path": "/binaryMediaTypes", "value": "image/jpeg"},
         {"op": "replace", "path": "/disableExecuteApiEndpoint", "value": "True"},
+        {
+            "op": "replace",
+            "path": "/policy",
+            "value": '{"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Principal": "*", "Action": '
+            '"execute-api:Invoke", "Resource": ["execute-api:/*"]}]}',
+        },
     ]
 
     response = client.update_rest_api(restApiId=api_id, patchOperations=patchOperations)
@@ -65,6 +71,8 @@ def test_update_rest_api():
             "version": "V1",
             "description": "new-description",
             "apiKeySource": "AUTHORIZER",
+            "policy": '{"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Principal": "*", "Action": '
+            '"execute-api:Invoke", "Resource": ["execute-api:/*"]}]}',
             "endpointConfiguration": {"types": ["EDGE"]},
             "tags": {},
             "disableExecuteApiEndpoint": True,
diff --git a/tests/test_core/test_moto_api.py b/tests/test_core/test_moto_api.py
index 3d69ba23b..cac92f034 100644
--- a/tests/test_core/test_moto_api.py
+++ b/tests/test_core/test_moto_api.py
@@ -5,8 +5,9 @@ import boto3
 import json
 import pytest
 from botocore.exceptions import ClientError
-from moto import mock_autoscaling, mock_sqs, settings
-from unittest import SkipTest
+from moto import mock_autoscaling, mock_s3, mock_sqs, settings
+from moto.core.model_instances import model_data, reset_model_data
+from unittest import SkipTest, TestCase
 
 base_url = (
     "http://localhost:5000"
@@ -73,3 +74,61 @@ def test_creation_error__data_api_still_returns_thing():
 
     names = [obj["name"] for obj in as_objects["FakeAutoScalingGroup"]]
     names.should.contain("test_asg")
+
+
+def test_model_data_is_emptied_as_necessary():
+    if settings.TEST_SERVER_MODE:
+        raise SkipTest("We're only interested in the decorator performance here")
+
+    # Reset any residual data
+    reset_model_data()
+
+    # No instances exist, because we have just reset it
+    for classes_per_service in model_data.values():
+        for _class in classes_per_service.values():
+            _class.instances.should.equal([])
+
+    with mock_sqs():
+        # When just starting a mock, it is empty
+        for classes_per_service in model_data.values():
+            for _class in classes_per_service.values():
+                _class.instances.should.equal([])
+
+        # After creating a queue, some data will be present
+        conn = boto3.client("sqs", region_name="us-west-1")
+        conn.create_queue(QueueName="queue1")
+
+        model_data["sqs"]["Queue"].instances.should.have.length_of(1)
+
+    # But after the mock ends, it is empty again
+    for classes_per_service in model_data.values():
+        for _class in classes_per_service.values():
+            _class.instances.should.equal([])
+
+    # When we have multiple/nested mocks, the data should still be present after the first mock ends
+    with mock_sqs():
+        conn = boto3.client("sqs", region_name="us-west-1")
+        conn.create_queue(QueueName="queue1")
+        with mock_s3():
+            # The data should still be here - instances should not reset if another mock is still active
+            model_data["sqs"]["Queue"].instances.should.have.length_of(1)
+        # The data should still be here - the inner mock has exited, but the outer mock is still active
+        model_data["sqs"]["Queue"].instances.should.have.length_of(1)
+
+
+@mock_sqs
+class TestModelDataResetForClassDecorator(TestCase):
+    def setUp(self):
+        if settings.TEST_SERVER_MODE:
+            raise SkipTest("We're only interested in the decorator performance here")
+
+        # No data is present at the beginning
+        for classes_per_service in model_data.values():
+            for _class in classes_per_service.values():
+                _class.instances.should.equal([])
+
+        conn = boto3.client("sqs", region_name="us-west-1")
+        conn.create_queue(QueueName="queue1")
+
+    def test_should_find_bucket(self):
+        model_data["sqs"]["Queue"].instances.should.have.length_of(1)
diff --git a/tests/test_dynamodb/test_dynamodb.py b/tests/test_dynamodb/test_dynamodb.py
index 8f3459ef9..2146184dc 100644
--- a/tests/test_dynamodb/test_dynamodb.py
+++ b/tests/test_dynamodb/test_dynamodb.py
@@ -4708,6 +4708,17 @@ def test_gsi_projection_type_include():
         }
     )
 
+    # Same when scanning the table
+    items = table.scan(IndexName="GSI-INC")["Items"]
+    items[0].should.equal(
+        {
+            "gsiK1PartitionKey": "gsi-pk",
+            "gsiK1SortKey": "gsi-sk",
+            "partitionKey": "pk-1",
+            "projectedAttribute": "lore ipsum",
+        }
+    )
+
 
 @mock_dynamodb
 def test_lsi_projection_type_keys_only():
@@ -4756,6 +4767,12 @@ def test_lsi_projection_type_keys_only():
         {"partitionKey": "pk-1", "sortKey": "sk-1", "lsiK1SortKey": "lsi-sk"}
     )
 
+    # Same when scanning the table
+    items = table.scan(IndexName="LSI")["Items"]
+    items[0].should.equal(
+        {"lsiK1SortKey": "lsi-sk", "partitionKey": "pk-1", "sortKey": "sk-1"}
+    )
+
 
 @mock_dynamodb
 @pytest.mark.parametrize(
diff --git a/tests/test_kms/test_kms_boto3.py b/tests/test_kms/test_kms_boto3.py
index f51b75129..f82d56309 100644
--- a/tests/test_kms/test_kms_boto3.py
+++ b/tests/test_kms/test_kms_boto3.py
@@ -43,19 +43,6 @@ def test_create_key_without_description():
     metadata.should.have.key("Description").equal("")
 
 
-@mock_kms
-def test_create_key_with_empty_content():
-    client_kms = boto3.client("kms", region_name="ap-northeast-1")
-    metadata = client_kms.create_key(Policy="my policy")["KeyMetadata"]
-    with pytest.raises(ClientError) as exc:
-        client_kms.encrypt(KeyId=metadata["KeyId"], Plaintext="")
-    err = exc.value.response["Error"]
-    err["Code"].should.equal("ValidationException")
-    err["Message"].should.equal(
-        "1 validation error detected: Value at 'plaintext' failed to satisfy constraint: Member must have length greater than or equal to 1"
-    )
-
-
 @mock_kms
 def test_create_key():
     conn = boto3.client("kms", region_name="us-east-1")
@@ -377,51 +364,6 @@ def test_generate_data_key():
     response["KeyId"].should.equal(key_arn)
 
 
-@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS)
-@mock_kms
-def test_encrypt(plaintext):
-    client = boto3.client("kms", region_name="us-west-2")
-
-    key = client.create_key(Description="key")
-    key_id = key["KeyMetadata"]["KeyId"]
-    key_arn = key["KeyMetadata"]["Arn"]
-
-    response = client.encrypt(KeyId=key_id, Plaintext=plaintext)
-    response["CiphertextBlob"].should_not.equal(plaintext)
-
-    # CiphertextBlob must NOT be base64-encoded
-    with pytest.raises(Exception):
-        base64.b64decode(response["CiphertextBlob"], validate=True)
-
-    response["KeyId"].should.equal(key_arn)
-
-
-@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS)
-@mock_kms
-def test_decrypt(plaintext):
-    client = boto3.client("kms", region_name="us-west-2")
-
-    key = client.create_key(Description="key")
-    key_id = key["KeyMetadata"]["KeyId"]
-    key_arn = key["KeyMetadata"]["Arn"]
-
-    encrypt_response = client.encrypt(KeyId=key_id, Plaintext=plaintext)
-
-    client.create_key(Description="key")
-    # CiphertextBlob must NOT be base64-encoded
-    with pytest.raises(Exception):
-        base64.b64decode(encrypt_response["CiphertextBlob"], validate=True)
-
-    decrypt_response = client.decrypt(CiphertextBlob=encrypt_response["CiphertextBlob"])
-
-    # Plaintext must NOT be base64-encoded
-    with pytest.raises(Exception):
-        base64.b64decode(decrypt_response["Plaintext"], validate=True)
-
-    decrypt_response["Plaintext"].should.equal(_get_encoded_value(plaintext))
-    decrypt_response["KeyId"].should.equal(key_arn)
-
-
 @pytest.mark.parametrize(
     "key_id",
     [
@@ -440,17 +382,6 @@ def test_invalid_key_ids(key_id):
         client.generate_data_key(KeyId=key_id, NumberOfBytes=5)
 
 
-@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS)
-@mock_kms
-def test_kms_encrypt(plaintext):
-    client = boto3.client("kms", region_name="us-east-1")
-    key = client.create_key(Description="key")
-    response = client.encrypt(KeyId=key["KeyMetadata"]["KeyId"], Plaintext=plaintext)
-
-    response = client.decrypt(CiphertextBlob=response["CiphertextBlob"])
-    response["Plaintext"].should.equal(_get_encoded_value(plaintext))
-
-
 @mock_kms
 def test_disable_key():
     client = boto3.client("kms", region_name="us-east-1")
@@ -738,69 +669,6 @@ def test_generate_data_key_without_plaintext_decrypt():
     assert "Plaintext" not in resp1
 
 
-@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS)
-@mock_kms
-def test_re_encrypt_decrypt(plaintext):
-    client = boto3.client("kms", region_name="us-west-2")
-
-    key_1 = client.create_key(Description="key 1")
-    key_1_id = key_1["KeyMetadata"]["KeyId"]
-    key_1_arn = key_1["KeyMetadata"]["Arn"]
-    key_2 = client.create_key(Description="key 2")
-    key_2_id = key_2["KeyMetadata"]["KeyId"]
-    key_2_arn = key_2["KeyMetadata"]["Arn"]
-
-    encrypt_response = client.encrypt(
-        KeyId=key_1_id, Plaintext=plaintext, EncryptionContext={"encryption": "context"}
-    )
-
-    re_encrypt_response = client.re_encrypt(
-        CiphertextBlob=encrypt_response["CiphertextBlob"],
-        SourceEncryptionContext={"encryption": "context"},
-        DestinationKeyId=key_2_id,
-        DestinationEncryptionContext={"another": "context"},
-    )
-
-    # CiphertextBlob must NOT be base64-encoded
-    with pytest.raises(Exception):
-        base64.b64decode(re_encrypt_response["CiphertextBlob"], validate=True)
-
-    re_encrypt_response["SourceKeyId"].should.equal(key_1_arn)
-    re_encrypt_response["KeyId"].should.equal(key_2_arn)
-
-    decrypt_response_1 = client.decrypt(
-        CiphertextBlob=encrypt_response["CiphertextBlob"],
-        EncryptionContext={"encryption": "context"},
-    )
-    decrypt_response_1["Plaintext"].should.equal(_get_encoded_value(plaintext))
-    decrypt_response_1["KeyId"].should.equal(key_1_arn)
-
-    decrypt_response_2 = client.decrypt(
-        CiphertextBlob=re_encrypt_response["CiphertextBlob"],
-        EncryptionContext={"another": "context"},
-    )
-    decrypt_response_2["Plaintext"].should.equal(_get_encoded_value(plaintext))
-    decrypt_response_2["KeyId"].should.equal(key_2_arn)
-
-    decrypt_response_1["Plaintext"].should.equal(decrypt_response_2["Plaintext"])
-
-
-@mock_kms
-def test_re_encrypt_to_invalid_destination():
-    client = boto3.client("kms", region_name="us-west-2")
-
-    key = client.create_key(Description="key 1")
-    key_id = key["KeyMetadata"]["KeyId"]
-
-    encrypt_response = client.encrypt(KeyId=key_id, Plaintext=b"some plaintext")
-
-    with pytest.raises(client.exceptions.NotFoundException):
-        client.re_encrypt(
-            CiphertextBlob=encrypt_response["CiphertextBlob"],
-            DestinationKeyId="alias/DoesNotExist",
-        )
-
-
 @pytest.mark.parametrize("number_of_bytes", [12, 44, 91, 1, 1024])
 @mock_kms
 def test_generate_random(number_of_bytes):
diff --git a/tests/test_kms/test_kms_encrypt.py b/tests/test_kms/test_kms_encrypt.py
new file mode 100644
index 000000000..6db34dcc3
--- /dev/null
+++ b/tests/test_kms/test_kms_encrypt.py
@@ -0,0 +1,176 @@
+import base64
+
+import boto3
+import sure  # noqa # pylint: disable=unused-import
+from botocore.exceptions import ClientError
+import pytest
+
+from moto import mock_kms
+from .test_kms_boto3 import PLAINTEXT_VECTORS, _get_encoded_value
+
+
+@mock_kms
+def test_create_key_with_empty_content():
+    client_kms = boto3.client("kms", region_name="ap-northeast-1")
+    metadata = client_kms.create_key(Policy="my policy")["KeyMetadata"]
+    with pytest.raises(ClientError) as exc:
+        client_kms.encrypt(KeyId=metadata["KeyId"], Plaintext="")
+    err = exc.value.response["Error"]
+    err["Code"].should.equal("ValidationException")
+    err["Message"].should.equal(
+        "1 validation error detected: Value at 'plaintext' failed to satisfy constraint: Member must have length greater than or equal to 1"
+    )
+
+
+@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS)
+@mock_kms
+def test_encrypt(plaintext):
+    client = boto3.client("kms", region_name="us-west-2")
+
+    key = client.create_key(Description="key")
+    key_id = key["KeyMetadata"]["KeyId"]
+    key_arn = key["KeyMetadata"]["Arn"]
+
+    response = client.encrypt(KeyId=key_id, Plaintext=plaintext)
+    response["CiphertextBlob"].should_not.equal(plaintext)
+
+    # CiphertextBlob must NOT be base64-encoded
+    with pytest.raises(Exception):
+        base64.b64decode(response["CiphertextBlob"], validate=True)
+
+    response["KeyId"].should.equal(key_arn)
+
+
+@mock_kms
+def test_encrypt_using_alias_name():
+    kms = boto3.client("kms", region_name="us-east-1")
+    key_details = kms.create_key()
+    key_alias = "alias/examplekey"
+    kms.create_alias(AliasName=key_alias, TargetKeyId=key_details["KeyMetadata"]["Arn"])
+
+    # Just ensure that they do not throw an error, i.e. verify that it's possible to call this method using the Alias
+    resp = kms.encrypt(KeyId=key_alias, Plaintext="hello")
+    kms.decrypt(CiphertextBlob=resp["CiphertextBlob"])
+
+
+@mock_kms
+def test_encrypt_using_alias_arn():
+    kms = boto3.client("kms", region_name="us-east-1")
+    key_details = kms.create_key()
+    key_alias = "alias/examplekey"
+    kms.create_alias(AliasName=key_alias, TargetKeyId=key_details["KeyMetadata"]["Arn"])
+
+    aliases = kms.list_aliases(KeyId=key_details["KeyMetadata"]["Arn"])["Aliases"]
+    my_alias = [a for a in aliases if a["AliasName"] == key_alias][0]
+
+    kms.encrypt(KeyId=my_alias["AliasArn"], Plaintext="hello")
+
+
+@mock_kms
+def test_encrypt_using_key_arn():
+    kms = boto3.client("kms", region_name="us-east-1")
+    key_details = kms.create_key()
+    key_alias = "alias/examplekey"
+    kms.create_alias(AliasName=key_alias, TargetKeyId=key_details["KeyMetadata"]["Arn"])
+
+    kms.encrypt(KeyId=key_details["KeyMetadata"]["Arn"], Plaintext="hello")
+
+
+@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS)
+@mock_kms
+def test_decrypt(plaintext):
+    client = boto3.client("kms", region_name="us-west-2")
+
+    key = client.create_key(Description="key")
+    key_id = key["KeyMetadata"]["KeyId"]
+    key_arn = key["KeyMetadata"]["Arn"]
+
+    encrypt_response = client.encrypt(KeyId=key_id, Plaintext=plaintext)
+
+    client.create_key(Description="key")
+    # CiphertextBlob must NOT be base64-encoded
+    with pytest.raises(Exception):
+        base64.b64decode(encrypt_response["CiphertextBlob"], validate=True)
+
+    decrypt_response = client.decrypt(CiphertextBlob=encrypt_response["CiphertextBlob"])
+
+    # Plaintext must NOT be base64-encoded
+    with pytest.raises(Exception):
+        base64.b64decode(decrypt_response["Plaintext"], validate=True)
+
+    decrypt_response["Plaintext"].should.equal(_get_encoded_value(plaintext))
+    decrypt_response["KeyId"].should.equal(key_arn)
+
+
+@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS)
+@mock_kms
+def test_kms_encrypt(plaintext):
+    client = boto3.client("kms", region_name="us-east-1")
+    key = client.create_key(Description="key")
+    response = client.encrypt(KeyId=key["KeyMetadata"]["KeyId"], Plaintext=plaintext)
+
+    response = client.decrypt(CiphertextBlob=response["CiphertextBlob"])
+    response["Plaintext"].should.equal(_get_encoded_value(plaintext))
+
+
+@pytest.mark.parametrize("plaintext", PLAINTEXT_VECTORS)
+@mock_kms
+def test_re_encrypt_decrypt(plaintext):
+    client = boto3.client("kms", region_name="us-west-2")
+
+    key_1 = client.create_key(Description="key 1")
+    key_1_id = key_1["KeyMetadata"]["KeyId"]
+    key_1_arn = key_1["KeyMetadata"]["Arn"]
+    key_2 = client.create_key(Description="key 2")
+    key_2_id = key_2["KeyMetadata"]["KeyId"]
+    key_2_arn = key_2["KeyMetadata"]["Arn"]
+
+    encrypt_response = client.encrypt(
+        KeyId=key_1_id, Plaintext=plaintext, EncryptionContext={"encryption": "context"}
+    )
+
+    re_encrypt_response = client.re_encrypt(
+        CiphertextBlob=encrypt_response["CiphertextBlob"],
+        SourceEncryptionContext={"encryption": "context"},
+        DestinationKeyId=key_2_id,
+        DestinationEncryptionContext={"another": "context"},
+    )
+
+    # CiphertextBlob must NOT be base64-encoded
+    with pytest.raises(Exception):
+        base64.b64decode(re_encrypt_response["CiphertextBlob"], validate=True)
+
+    re_encrypt_response["SourceKeyId"].should.equal(key_1_arn)
+    re_encrypt_response["KeyId"].should.equal(key_2_arn)
+
+    decrypt_response_1 = client.decrypt(
+        CiphertextBlob=encrypt_response["CiphertextBlob"],
+        EncryptionContext={"encryption": "context"},
+    )
+    decrypt_response_1["Plaintext"].should.equal(_get_encoded_value(plaintext))
+    decrypt_response_1["KeyId"].should.equal(key_1_arn)
+
+    decrypt_response_2 = client.decrypt(
+        CiphertextBlob=re_encrypt_response["CiphertextBlob"],
+        EncryptionContext={"another": "context"},
+    )
+    decrypt_response_2["Plaintext"].should.equal(_get_encoded_value(plaintext))
+    decrypt_response_2["KeyId"].should.equal(key_2_arn)
+
+    decrypt_response_1["Plaintext"].should.equal(decrypt_response_2["Plaintext"])
+
+
+@mock_kms
+def test_re_encrypt_to_invalid_destination():
+    client = boto3.client("kms", region_name="us-west-2")
+
+    key = client.create_key(Description="key 1")
+    key_id = key["KeyMetadata"]["KeyId"]
+
+    encrypt_response = client.encrypt(KeyId=key_id, Plaintext=b"some plaintext")
+
+    with pytest.raises(client.exceptions.NotFoundException):
+        client.re_encrypt(
+            CiphertextBlob=encrypt_response["CiphertextBlob"],
+            DestinationKeyId="alias/DoesNotExist",
+        )
diff --git a/tests/test_rds/test_rds.py b/tests/test_rds/test_rds.py
index cb452c06b..653e39744 100644
--- a/tests/test_rds/test_rds.py
+++ b/tests/test_rds/test_rds.py
@@ -1228,6 +1228,9 @@ def test_create_option_group():
         "test option group"
     )
     option_group["OptionGroup"]["MajorEngineVersion"].should.equal("5.6")
+    option_group["OptionGroup"]["OptionGroupArn"].should.equal(
+        f"arn:aws:rds:us-west-2:{ACCOUNT_ID}:og:test"
+    )
 
 
 @mock_rds
diff --git a/tests/test_s3/test_s3_auth.py b/tests/test_s3/test_s3_auth.py
index c915ee26e..35288baf9 100644
--- a/tests/test_s3/test_s3_auth.py
+++ b/tests/test_s3/test_s3_auth.py
@@ -52,6 +52,11 @@ def test_head_bucket_with_correct_credentials():
         aws_secret_access_key=iam_keys["SecretAccessKey"],
     )
 
+    # Verify we can make calls that contain a querystring
+    # Specifically, verify that we are able to build/match the AWS signature for a URL with a querystring
+    s3.get_bucket_location(Bucket="mock_bucket")
+    s3.list_objects_v2(Bucket="mock_bucket")
+
 
 @set_initial_no_auth_action_count(4)
 @mock_s3
diff --git a/tests/test_s3/test_s3_file_handles.py b/tests/test_s3/test_s3_file_handles.py
index cb4366500..70602145d 100644
--- a/tests/test_s3/test_s3_file_handles.py
+++ b/tests/test_s3/test_s3_file_handles.py
@@ -168,6 +168,7 @@ class TestS3FileHandleClosures(TestCase):
     @verify_zero_warnings
     def test_overwrite_versioned_upload(self):
         self.s3.put_object("versioned-bucket", "my-key", "x" * 10_000_000)
+        self.s3.put_object("versioned-bucket", "my-key", "x" * 10_000_000)
 
     @verify_zero_warnings
     def test_multiple_versions_upload(self):
@@ -262,6 +263,21 @@ class TestS3FileHandleClosuresUsingMocks(TestCase):
             version = self.s3.put_object(Bucket="foo", Key="b", Body="s")["VersionId"]
             self.s3.delete_object(Bucket="foo", Key="b", VersionId=version)
 
+    @verify_zero_warnings
+    def test_update_versioned_object__while_looping(self):
+        for _ in (1, 2):
+            with mock_s3():
+                self.s3.create_bucket(Bucket="foo")
+                self.s3.put_bucket_versioning(
+                    Bucket="foo",
+                    VersioningConfiguration={
+                        "Status": "Enabled",
+                        "MFADelete": "Disabled",
+                    },
+                )
+                self.s3.put_object(Bucket="foo", Key="bar", Body="stuff")
+                self.s3.put_object(Bucket="foo", Key="bar", Body="stuff2")
+
 
 def test_verify_key_can_be_copied_after_disposing():
     # https://github.com/getmoto/moto/issues/5588