Repository: getmoto/moto
Pull request #7479 (2024-03-16 18:42:35)

Server: check ready state with `threading.Event`
This PR aims to replace the busy waiting of the `ThreadedMotoServer` startup with the more clear `threading.Event` object. This change will also reduce the `ThreadedMotoServer.start` method execution time, as the Werkzeug server startup time is usually less than 0.1 seconds.


Patch:
diff --git a/IMPLEMENTATION_COVERAGE.md b/IMPLEMENTATION_COVERAGE.md
index fedeb40d1..a00754251 100644
--- a/IMPLEMENTATION_COVERAGE.md
+++ b/IMPLEMENTATION_COVERAGE.md
@@ -6218,13 +6218,13 @@
 
 ## resiliencehub
 <details>
-<summary>18% implemented</summary>
+<summary>31% implemented</summary>
 
 - [ ] add_draft_app_version_resource_mappings
 - [ ] batch_update_recommendation_status
 - [X] create_app
-- [ ] create_app_version_app_component
-- [ ] create_app_version_resource
+- [X] create_app_version_app_component
+- [X] create_app_version_resource
 - [ ] create_recommendation_template
 - [X] create_resiliency_policy
 - [ ] delete_app
@@ -6243,17 +6243,17 @@
 - [ ] describe_app_version_template
 - [ ] describe_draft_app_version_resources_import_status
 - [X] describe_resiliency_policy
-- [ ] import_resources_to_draft_app_version
+- [X] import_resources_to_draft_app_version
 - [ ] list_alarm_recommendations
 - [ ] list_app_assessment_compliance_drifts
 - [X] list_app_assessments
 - [ ] list_app_component_compliances
 - [ ] list_app_component_recommendations
 - [ ] list_app_input_sources
-- [ ] list_app_version_app_components
+- [X] list_app_version_app_components
 - [ ] list_app_version_resource_mappings
-- [ ] list_app_version_resources
-- [ ] list_app_versions
+- [X] list_app_version_resources
+- [X] list_app_versions
 - [X] list_apps
 - [ ] list_recommendation_templates
 - [X] list_resiliency_policies
@@ -6262,7 +6262,7 @@
 - [X] list_tags_for_resource
 - [ ] list_test_recommendations
 - [ ] list_unsupported_app_version_resources
-- [ ] publish_app_version
+- [X] publish_app_version
 - [ ] put_draft_app_version_template
 - [ ] remove_draft_app_version_resource_mappings
 - [ ] resolve_app_version_resources
diff --git a/docs/docs/services/resiliencehub.rst b/docs/docs/services/resiliencehub.rst
index b326081f7..1a0eddf09 100644
--- a/docs/docs/services/resiliencehub.rst
+++ b/docs/docs/services/resiliencehub.rst
@@ -21,8 +21,8 @@ resiliencehub
         The ClientToken-parameter is not yet implemented
         
 
-- [ ] create_app_version_app_component
-- [ ] create_app_version_resource
+- [X] create_app_version_app_component
+- [X] create_app_version_resource
 - [ ] create_recommendation_template
 - [X] create_resiliency_policy
   
@@ -45,17 +45,17 @@ resiliencehub
 - [ ] describe_app_version_template
 - [ ] describe_draft_app_version_resources_import_status
 - [X] describe_resiliency_policy
-- [ ] import_resources_to_draft_app_version
+- [X] import_resources_to_draft_app_version
 - [ ] list_alarm_recommendations
 - [ ] list_app_assessment_compliance_drifts
 - [X] list_app_assessments
 - [ ] list_app_component_compliances
 - [ ] list_app_component_recommendations
 - [ ] list_app_input_sources
-- [ ] list_app_version_app_components
+- [X] list_app_version_app_components
 - [ ] list_app_version_resource_mappings
-- [ ] list_app_version_resources
-- [ ] list_app_versions
+- [X] list_app_version_resources
+- [X] list_app_versions
 - [X] list_apps
   
         The FromAssessmentTime/ToAssessmentTime-parameters are not yet implemented
@@ -68,7 +68,7 @@ resiliencehub
 - [X] list_tags_for_resource
 - [ ] list_test_recommendations
 - [ ] list_unsupported_app_version_resources
-- [ ] publish_app_version
+- [X] publish_app_version
 - [ ] put_draft_app_version_template
 - [ ] remove_draft_app_version_resource_mappings
 - [ ] resolve_app_version_resources
diff --git a/moto/autoscaling/models.py b/moto/autoscaling/models.py
index 2f27e3610..de47e2160 100644
--- a/moto/autoscaling/models.py
+++ b/moto/autoscaling/models.py
@@ -1,5 +1,6 @@
 import itertools
 from collections import OrderedDict
+from datetime import datetime
 from typing import Any, Dict, List, Optional, Tuple, Union
 
 from moto.core.base_backend import BackendDict, BaseBackend
@@ -439,6 +440,7 @@ class FakeAutoScalingGroup(CloudFormationModel):
         mixed_instance_policy: Optional[Dict[str, Any]],
         capacity_rebalance: bool,
         new_instances_protected_from_scale_in: bool = False,
+        created_time: datetime = datetime.now(),
     ):
         self.autoscaling_backend = autoscaling_backend
         self.ec2_backend = ec2_backend
@@ -483,6 +485,7 @@ class FakeAutoScalingGroup(CloudFormationModel):
 
         self.metrics: List[str] = []
         self.warm_pool: Optional[FakeWarmPool] = None
+        self.created_time = created_time
 
     @property
     def tags(self) -> List[Dict[str, str]]:
diff --git a/moto/autoscaling/responses.py b/moto/autoscaling/responses.py
index e9aa149ca..23a1ab1f9 100644
--- a/moto/autoscaling/responses.py
+++ b/moto/autoscaling/responses.py
@@ -833,7 +833,7 @@ DESCRIBE_AUTOSCALING_GROUPS_TEMPLATE = """<DescribeAutoScalingGroupsResponse xml
         </SuspendedProcesses>
         <AutoScalingGroupName>{{ group.name }}</AutoScalingGroupName>
         <HealthCheckType>{{ group.health_check_type }}</HealthCheckType>
-        <CreatedTime>2013-05-06T17:47:15.107Z</CreatedTime>
+        <CreatedTime>{{ group.created_time }}</CreatedTime>
         {% if group.launch_config_name %}
         <LaunchConfigurationName>{{ group.launch_config_name }}</LaunchConfigurationName>
         {% elif group.mixed_instance_policy %}
diff --git a/moto/dynamodb/models/table.py b/moto/dynamodb/models/table.py
index aa7596694..145c892fa 100644
--- a/moto/dynamodb/models/table.py
+++ b/moto/dynamodb/models/table.py
@@ -744,9 +744,10 @@ class Table(CloudFormationModel):
             # Cycle through the previous page of results
             # When we encounter our start key, we know we've reached the end of the previous page
             if processing_previous_page:
-                if self._item_equals_dct(result, exclusive_start_key):
+                if self._item_smaller_than_dct(result, exclusive_start_key):
+                    continue
+                else:
                     processing_previous_page = False
-                continue
 
             # Check wether we've reached the limit of our result set
             # That can be either in number, or in size
@@ -868,9 +869,10 @@ class Table(CloudFormationModel):
             # Cycle through the previous page of results
             # When we encounter our start key, we know we've reached the end of the previous page
             if processing_previous_page:
-                if self._item_equals_dct(item, exclusive_start_key):
+                if self._item_smaller_than_dct(item, exclusive_start_key):
+                    continue
+                else:
                     processing_previous_page = False
-                continue
 
             # Check wether we've reached the limit of our result set
             # That can be either in number, or in size
@@ -921,12 +923,13 @@ class Table(CloudFormationModel):
 
         return results, scanned_count, last_evaluated_key
 
-    def _item_equals_dct(self, item: Item, dct: Dict[str, Any]) -> bool:
+    def _item_smaller_than_dct(self, item: Item, dct: Dict[str, Any]) -> bool:
         hash_key = DynamoType(dct.get(self.hash_key_attr))  # type: ignore[arg-type]
         range_key = dct.get(self.range_key_attr) if self.range_key_attr else None
         if range_key is not None:
             range_key = DynamoType(range_key)
-        return item.hash_key == hash_key and item.range_key == range_key
+            return item.hash_key <= hash_key and item.range_key <= range_key
+        return item.hash_key <= hash_key
 
     def _get_last_evaluated_key(
         self, last_result: Item, index_name: Optional[str]
diff --git a/moto/moto_server/threaded_moto_server.py b/moto/moto_server/threaded_moto_server.py
index 8849ade6f..32f9da34e 100644
--- a/moto/moto_server/threaded_moto_server.py
+++ b/moto/moto_server/threaded_moto_server.py
@@ -1,5 +1,4 @@
-import time
-from threading import Thread
+from threading import Event, Thread
 from typing import Optional
 
 from werkzeug.serving import BaseWSGIServer, make_server
@@ -11,20 +10,19 @@ class ThreadedMotoServer:
     def __init__(
         self, ip_address: str = "0.0.0.0", port: int = 5000, verbose: bool = True
     ):
-
         self._port = port
 
         self._thread: Optional[Thread] = None
         self._ip_address = ip_address
         self._server: Optional[BaseWSGIServer] = None
-        self._server_ready = False
+        self._server_ready_event = Event()
         self._verbose = verbose
 
     def _server_entry(self) -> None:
         app = DomainDispatcherApplication(create_backend_app)
 
         self._server = make_server(self._ip_address, self._port, app, True)
-        self._server_ready = True
+        self._server_ready_event.set()
         self._server.serve_forever()
 
     def start(self) -> None:
@@ -34,11 +32,10 @@ class ThreadedMotoServer:
             )
         self._thread = Thread(target=self._server_entry, daemon=True)
         self._thread.start()
-        while not self._server_ready:
-            time.sleep(0.1)
+        self._server_ready_event.wait()
 
     def stop(self) -> None:
-        self._server_ready = False
+        self._server_ready_event.clear()
         if self._server:
             self._server.shutdown()
 
diff --git a/moto/resiliencehub/exceptions.py b/moto/resiliencehub/exceptions.py
index 88c400049..8eac01a43 100644
--- a/moto/resiliencehub/exceptions.py
+++ b/moto/resiliencehub/exceptions.py
@@ -12,6 +12,11 @@ class AppNotFound(ResourceNotFound):
         super().__init__(f"App not found for appArn {arn}")
 
 
+class AppVersionNotFound(ResourceNotFound):
+    def __init__(self) -> None:
+        super().__init__("App Version not found")
+
+
 class ResiliencyPolicyNotFound(ResourceNotFound):
     def __init__(self, arn: str):
         super().__init__(f"ResiliencyPolicy {arn} not found")
diff --git a/moto/resiliencehub/models.py b/moto/resiliencehub/models.py
index 173ed2437..8a5cf568d 100644
--- a/moto/resiliencehub/models.py
+++ b/moto/resiliencehub/models.py
@@ -1,4 +1,4 @@
-from typing import Any, Dict, List
+from typing import Any, Dict, List, Optional
 
 from moto.core.base_backend import BackendDict, BaseBackend
 from moto.core.common_models import BaseModel
@@ -7,7 +7,7 @@ from moto.moto_api._internal import mock_random
 from moto.utilities.paginator import paginate
 from moto.utilities.tagging_service import TaggingService
 
-from .exceptions import AppNotFound, ResiliencyPolicyNotFound
+from .exceptions import AppNotFound, AppVersionNotFound, ResiliencyPolicyNotFound
 
 PAGINATION_MODEL = {
     "list_apps": {
@@ -25,6 +25,20 @@ PAGINATION_MODEL = {
 }
 
 
+class AppComponent(BaseModel):
+    def __init__(self, _id: str, name: str, _type: str):
+        self.id = _id
+        self.name = name
+        self.type = _type
+
+    def to_json(self) -> Dict[str, Any]:
+        return {
+            "id": self.id,
+            "name": self.name,
+            "type": self.type,
+        }
+
+
 class App(BaseModel):
     def __init__(
         self,
@@ -48,6 +62,16 @@ class App(BaseModel):
         self.policy_arn = policy_arn
         self.resilience_score = 0.0
         self.status = "Active"
+        self.app_versions: List[AppVersion] = []
+
+        app_version = AppVersion(app_arn=self.arn, version_name=None, identifier=0)
+        self.app_versions.append(app_version)
+
+    def get_version(self, version_name: str) -> "AppVersion":
+        for v in self.app_versions:
+            if v.app_version == version_name:
+                return v
+        raise AppVersionNotFound
 
     def to_json(self) -> Dict[str, Any]:
         resp = {
@@ -55,6 +79,7 @@ class App(BaseModel):
             "assessmentSchedule": self.assessment_schedule,
             "complianceStatus": self.compliance_status,
             "creationTime": self.creation_time,
+            "driftStatus": "NotChecked",
             "name": self.name,
             "resilienceScore": self.resilience_score,
             "status": self.status,
@@ -71,6 +96,54 @@ class App(BaseModel):
         return resp
 
 
+class Resource:
+    def __init__(
+        self,
+        logical_resource_id: Dict[str, Any],
+        physical_resource_id: str,
+        resource_type: str,
+        components: List[AppComponent],
+    ):
+        self.logical_resource_id = logical_resource_id
+        self.physical_resource_id = physical_resource_id
+        self.resource_type = resource_type
+        self.components = components
+
+    def to_json(self) -> Dict[str, Any]:
+        return {
+            "appComponents": [c.to_json() for c in self.components],
+            "resourceType": self.resource_type,
+            "logicalResourceId": self.logical_resource_id,
+            "physicalResourceId": {"identifier": self.physical_resource_id},
+            "resourceName": self.logical_resource_id["identifier"],
+        }
+
+
+class AppVersion(BaseModel):
+    def __init__(self, app_arn: str, version_name: Optional[str], identifier: int):
+        self.app_arn = app_arn
+        self.eks_sources: List[Dict[str, Any]] = []
+        self.source_arns: List[str] = []
+        self.terraform_sources: List[Dict[str, str]] = []
+        self.app_version = "release" if version_name else "draft"
+        self.identifier = identifier
+        self.creation_time = unix_time()
+        self.version_name = version_name
+        self.app_components: List[AppComponent] = []
+        self.status = "Pending"
+        self.resources: List[Resource] = []
+
+    def to_json(self) -> Dict[str, Any]:
+        resp = {
+            "appVersion": self.app_version,
+            "creationTime": self.creation_time,
+            "identifier": self.identifier,
+        }
+        if self.version_name:
+            resp["versionName"] = self.version_name
+        return resp
+
+
 class Policy(BaseModel):
     def __init__(
         self,
@@ -208,5 +281,88 @@ class ResilienceHubBackend(BaseBackend):
     def list_tags_for_resource(self, resource_arn: str) -> Dict[str, str]:
         return self.tagger.get_tag_dict_for_resource(resource_arn)
 
+    def import_resources_to_draft_app_version(
+        self,
+        app_arn: str,
+        eks_sources: List[Dict[str, Any]],
+        source_arns: List[str],
+        terraform_sources: List[Dict[str, str]],
+    ) -> AppVersion:
+        app = self.describe_app(app_arn)
+        app_version = app.get_version("draft")
+
+        app_version.eks_sources.extend(eks_sources)
+        app_version.source_arns.extend(source_arns)
+        app_version.terraform_sources.extend(terraform_sources)
+
+        # Default AppComponent when importing data
+        # AWS seems to create other components as well, based on the provided sources
+        app_version.app_components.append(
+            AppComponent(
+                _id="appcommon",
+                name="appcommon",
+                _type="AWS::ResilienceHub::AppCommonAppComponent",
+            )
+        )
+        return app_version
+
+    def create_app_version_app_component(
+        self, app_arn: str, name: str, _type: str
+    ) -> AppComponent:
+        app = self.describe_app(app_arn)
+        app_version = app.get_version("draft")
+        component = AppComponent(_id=name, name=name, _type=_type)
+        app_version.app_components.append(component)
+        return component
+
+    def list_app_version_app_components(
+        self, app_arn: str, app_version: str
+    ) -> List[AppComponent]:
+        app = self.describe_app(app_arn)
+        return app.get_version(app_version).app_components
+
+    def create_app_version_resource(
+        self,
+        app_arn: str,
+        app_components: List[str],
+        logical_resource_id: Dict[str, str],
+        physical_resource_id: str,
+        resource_type: str,
+    ) -> Resource:
+        app = self.describe_app(app_arn)
+        app_version = app.get_version("draft")
+
+        components = [c for c in app_version.app_components if c.id in app_components]
+
+        resource = Resource(
+            logical_resource_id=logical_resource_id,
+            physical_resource_id=physical_resource_id,
+            resource_type=resource_type,
+            components=components,
+        )
+        app_version.resources.append(resource)
+        return resource
+
+    def list_app_version_resources(
+        self, app_arn: str, app_version: str
+    ) -> List[Resource]:
+        app = self.describe_app(app_arn)
+        return app.get_version(app_version).resources
+
+    def list_app_versions(self, app_arn: str) -> List[AppVersion]:
+        app = self.describe_app(app_arn)
+        return app.app_versions
+
+    def publish_app_version(self, app_arn: str, version_name: str) -> AppVersion:
+        app = self.describe_app(app_arn)
+        version = AppVersion(
+            app_arn=app_arn, version_name=version_name, identifier=len(app.app_versions)
+        )
+        for old_version in app.app_versions:
+            if old_version.app_version == "release":
+                old_version.app_version = str(old_version.identifier)
+        app.app_versions.append(version)
+        return version
+
 
 resiliencehub_backends = BackendDict(ResilienceHubBackend, "resiliencehub")
diff --git a/moto/resiliencehub/responses.py b/moto/resiliencehub/responses.py
index c9b530613..7a8f3b903 100644
--- a/moto/resiliencehub/responses.py
+++ b/moto/resiliencehub/responses.py
@@ -157,3 +157,99 @@ class ResilienceHubResponse(BaseResponse):
             resource_arn=resource_arn,
         )
         return json.dumps(dict(tags=tags))
+
+    def import_resources_to_draft_app_version(self) -> str:
+        app_arn = self._get_param("appArn")
+        eks_sources = self._get_param("eksSources")
+        source_arns = self._get_param("sourceArns")
+        terraform_sources = self._get_param("terraformSources")
+
+        app_version = self.resiliencehub_backend.import_resources_to_draft_app_version(
+            app_arn=app_arn,
+            eks_sources=eks_sources,
+            source_arns=source_arns,
+            terraform_sources=terraform_sources,
+        )
+        return json.dumps(
+            {
+                "appArn": app_version.app_arn,
+                "appVersion": app_version.version_name,
+                "eksSources": eks_sources,
+                "sourceArns": source_arns,
+                "status": app_version.status,
+                "terraformSources": terraform_sources,
+            }
+        )
+
+    def list_app_version_app_components(self) -> str:
+        app_arn = self._get_param("appArn")
+        app_version = self._get_param("appVersion")
+        components = self.resiliencehub_backend.list_app_version_app_components(
+            app_arn, app_version
+        )
+        return json.dumps(
+            {
+                "appArn": app_arn,
+                "appVersion": app_version,
+                "appComponents": [c.to_json() for c in components],
+            }
+        )
+
+    def create_app_version_app_component(self) -> str:
+        app_arn = self._get_param("appArn")
+        name = self._get_param("name")
+        _type = self._get_param("type")
+        component = self.resiliencehub_backend.create_app_version_app_component(
+            app_arn=app_arn,
+            name=name,
+            _type=_type,
+        )
+        return json.dumps(
+            {
+                "appArn": app_arn,
+                "appComponent": component.to_json(),
+                "appVersion": "draft",
+            }
+        )
+
+    def create_app_version_resource(self) -> str:
+        app_arn = self._get_param("appArn")
+        app_components = self._get_param("appComponents")
+        logical_resource_id = self._get_param("logicalResourceId")
+        physical_resource_id = self._get_param("physicalResourceId")
+        resource_type = self._get_param("resourceType")
+
+        resource = self.resiliencehub_backend.create_app_version_resource(
+            app_arn=app_arn,
+            app_components=app_components,
+            logical_resource_id=logical_resource_id,
+            physical_resource_id=physical_resource_id,
+            resource_type=resource_type,
+        )
+
+        return json.dumps(
+            {
+                "appArn": app_arn,
+                "appVersion": "draft",
+                "physicalResource": resource.to_json(),
+            }
+        )
+
+    def list_app_version_resources(self) -> str:
+        app_arn = self._get_param("appArn")
+        app_version = self._get_param("appVersion")
+        resources = self.resiliencehub_backend.list_app_version_resources(
+            app_arn, app_version
+        )
+        return json.dumps({"physicalResources": [r.to_json() for r in resources]})
+
+    def list_app_versions(self) -> str:
+        app_arn = self._get_param("appArn")
+        versions = self.resiliencehub_backend.list_app_versions(app_arn)
+        return json.dumps({"appVersions": [v.to_json() for v in versions]})
+
+    def publish_app_version(self) -> str:
+        app_arn = self._get_param("appArn")
+        version_name = self._get_param("versionName")
+        version = self.resiliencehub_backend.publish_app_version(app_arn, version_name)
+        return json.dumps({"appArn": app_arn, **version.to_json()})
diff --git a/moto/resiliencehub/urls.py b/moto/resiliencehub/urls.py
index a39663688..09e96ef08 100644
--- a/moto/resiliencehub/urls.py
+++ b/moto/resiliencehub/urls.py
@@ -7,12 +7,19 @@ url_bases = [
 
 url_paths = {
     "{0}/create-app$": ResilienceHubResponse.dispatch,
+    "{0}/create-app-version-app-component$": ResilienceHubResponse.dispatch,
+    "{0}/create-app-version-resource$": ResilienceHubResponse.dispatch,
     "{0}/create-resiliency-policy$": ResilienceHubResponse.dispatch,
     "{0}/describe-app$": ResilienceHubResponse.dispatch,
     "{0}/describe-resiliency-policy$": ResilienceHubResponse.dispatch,
+    "{0}/import-resources-to-draft-app-version$": ResilienceHubResponse.dispatch,
     "{0}/list-apps$": ResilienceHubResponse.dispatch,
     "{0}/list-app-assessments$": ResilienceHubResponse.dispatch,
+    "{0}/list-app-versions$": ResilienceHubResponse.dispatch,
+    "{0}/list-app-version-app-components$": ResilienceHubResponse.dispatch,
+    "{0}/list-app-version-resources$": ResilienceHubResponse.dispatch,
     "{0}/list-resiliency-policies$": ResilienceHubResponse.dispatch,
+    "{0}/publish-app-version$": ResilienceHubResponse.dispatch,
     "{0}/tags/.+$": ResilienceHubResponse.dispatch,
     "{0}/tags/(?P<arn_prefix>[^/]+)/(?P<workspace_id>[^/]+)$": ResilienceHubResponse.method_dispatch(
         ResilienceHubResponse.tags  # type: ignore
diff --git a/moto/ssm/resources/regions.json b/moto/ssm/resources/regions.json
index 310b48e7b..bdc7a1a43 100644
--- a/moto/ssm/resources/regions.json
+++ b/moto/ssm/resources/regions.json
@@ -1531,6 +1531,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -3164,6 +3173,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -3308,6 +3326,11 @@
             "geolocationRegion": {
               "Value": "JP-13"
             },
+            "local-zones": {
+              "apne1-tpe1-az1": {
+                "Value": "apne1-tpe1-az1"
+              }
+            },
             "longName": {
               "Value": "Asia Pacific (Tokyo)"
             },
@@ -5778,6 +5801,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -8172,6 +8204,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -9789,6 +9830,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -11997,6 +12047,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -13258,6 +13317,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -15757,6 +15825,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -15892,9 +15969,6 @@
                   "Value": "HTTPS"
                 }
               },
-              "wam": {
-                "Value": "wam"
-              },
               "wellarchitectedtool": {
                 "Value": "wellarchitectedtool",
                 "endpoint": {
@@ -18451,6 +18525,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -18607,9 +18690,6 @@
                   "Value": "HTTPS"
                 }
               },
-              "wam": {
-                "Value": "wam"
-              },
               "wellarchitectedtool": {
                 "Value": "wellarchitectedtool",
                 "endpoint": {
@@ -19946,6 +20026,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -20604,6 +20693,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "identity-center": {
+                "Value": "identity-center",
+                "endpoint": {
+                  "Value": "sso.ap-southeast-4.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "identitystore": {
                 "Value": "identitystore",
                 "endpoint": {
@@ -21123,6 +21221,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "sso-oidc": {
+                "Value": "sso-oidc",
+                "endpoint": {
+                  "Value": "oidc.ap-southeast-4.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "stepfunctions": {
                 "Value": "stepfunctions",
                 "endpoint": {
@@ -21150,6 +21257,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -23377,6 +23493,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -23680,6 +23805,15 @@
               "artifact": {
                 "Value": "artifact"
               },
+              "athena": {
+                "Value": "athena",
+                "endpoint": {
+                  "Value": "athena.ca-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "aurora": {
                 "Value": "aurora",
                 "endpoint": {
@@ -23707,6 +23841,15 @@
                   "Value": "HTTPS, HTTP"
                 }
               },
+              "backup": {
+                "Value": "backup",
+                "endpoint": {
+                  "Value": "backup.ca-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "batch": {
                 "Value": "batch",
                 "endpoint": {
@@ -24016,6 +24159,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "kinesisanalytics": {
+                "Value": "kinesisanalytics",
+                "endpoint": {
+                  "Value": "kinesisanalytics.ca-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "kms": {
                 "Value": "kms",
                 "endpoint": {
@@ -24328,6 +24480,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -24986,6 +25147,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "fsx-openzfs": {
+                "Value": "fsx-openzfs",
+                "endpoint": {
+                  "Value": "fsx.cn-north-1.amazonaws.com.cn"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "fsx-windows": {
                 "Value": "fsx-windows",
                 "endpoint": {
@@ -26406,6 +26576,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "fsx-openzfs": {
+                "Value": "fsx-openzfs",
+                "endpoint": {
+                  "Value": "fsx.cn-northwest-1.amazonaws.com.cn"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "fsx-windows": {
                 "Value": "fsx-windows",
                 "endpoint": {
@@ -29709,6 +29888,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -30204,6 +30392,24 @@
                   "Value": "HTTPS"
                 }
               },
+              "cognito-identity": {
+                "Value": "cognito-identity",
+                "endpoint": {
+                  "Value": "cognito-identity.eu-central-2.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "cognito-idp": {
+                "Value": "cognito-idp",
+                "endpoint": {
+                  "Value": "cognito-idp.eu-central-2.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "compute-optimizer": {
                 "Value": "compute-optimizer",
                 "endpoint": {
@@ -30468,6 +30674,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "fsx-openzfs": {
+                "Value": "fsx-openzfs",
+                "endpoint": {
+                  "Value": "fsx.eu-central-2.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "fsx-windows": {
                 "Value": "fsx-windows",
                 "endpoint": {
@@ -31047,6 +31262,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -33028,6 +33252,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -34625,6 +34858,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -35268,6 +35510,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "fsx-openzfs": {
+                "Value": "fsx-openzfs",
+                "endpoint": {
+                  "Value": "fsx.eu-south-2.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "fsx-windows": {
                 "Value": "fsx-windows",
                 "endpoint": {
@@ -35832,6 +36083,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -38509,7 +38769,7 @@
               "support": {
                 "Value": "support",
                 "endpoint": {
-                  "Value": "support.us-east-1.amazonaws.com"
+                  "Value": "support.eu-west-1.amazonaws.com"
                 },
                 "protocols": {
                   "Value": "HTTPS"
@@ -38665,9 +38925,6 @@
                   "Value": "HTTPS"
                 }
               },
-              "wam": {
-                "Value": "wam"
-              },
               "wellarchitectedtool": {
                 "Value": "wellarchitectedtool",
                 "endpoint": {
@@ -40388,6 +40645,15 @@
                   "Value": "HTTPS, HTTP"
                 }
               },
+              "neptune-graph": {
+                "Value": "neptune-graph",
+                "endpoint": {
+                  "Value": "neptune-graph.eu-west-2.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "network-firewall": {
                 "Value": "network-firewall",
                 "endpoint": {
@@ -41006,6 +41272,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -43037,6 +43312,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -44337,6 +44621,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -45682,6 +45975,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -47306,6 +47608,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -49260,6 +49571,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -49432,12 +49752,6 @@
               "use1-bos1-az1": {
                 "Value": "use1-bos1-az1"
               },
-              "use1-chi1-az1": {
-                "Value": "use1-chi1-az1"
-              },
-              "use1-dfw1-az1": {
-                "Value": "use1-dfw1-az1"
-              },
               "use1-lim1-az1": {
                 "Value": "use1-lim1-az1"
               },
@@ -52509,9 +52823,6 @@
                   "Value": "HTTPS"
                 }
               },
-              "wam": {
-                "Value": "wam"
-              },
               "wellarchitectedtool": {
                 "Value": "wellarchitectedtool",
                 "endpoint": {
@@ -54981,6 +55292,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -55762,6 +56082,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "fsx-openzfs": {
+                "Value": "fsx-openzfs",
+                "endpoint": {
+                  "Value": "fsx.us-gov-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "fsx-windows": {
                 "Value": "fsx-windows",
                 "endpoint": {
@@ -56344,6 +56673,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "signer": {
+                "Value": "signer",
+                "endpoint": {
+                  "Value": "signer.us-gov-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "simspaceweaver": {
                 "Value": "simspaceweaver",
                 "endpoint": {
@@ -56425,6 +56763,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-gov-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -57245,6 +57592,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "fsx-openzfs": {
+                "Value": "fsx-openzfs",
+                "endpoint": {
+                  "Value": "fsx.us-gov-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "fsx-windows": {
                 "Value": "fsx-windows",
                 "endpoint": {
@@ -57956,6 +58312,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "signer": {
+                "Value": "signer",
+                "endpoint": {
+                  "Value": "signer.us-gov-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "simspaceweaver": {
                 "Value": "simspaceweaver",
                 "endpoint": {
@@ -60096,6 +60461,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "support": {
+                "Value": "support",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "swf": {
                 "Value": "swf",
                 "endpoint": {
@@ -60274,9 +60648,6 @@
               "usw2-pdx1-az1": {
                 "Value": "usw2-pdx1-az1"
               },
-              "usw2-phx1-az1": {
-                "Value": "usw2-phx1-az1"
-              },
               "usw2-phx2-az1": {
                 "Value": "usw2-phx2-az1"
               }
@@ -63012,7 +63383,7 @@
               "support": {
                 "Value": "support",
                 "endpoint": {
-                  "Value": "support.us-east-1.amazonaws.com"
+                  "Value": "support.us-west-2.amazonaws.com"
                 },
                 "protocols": {
                   "Value": "HTTPS"
@@ -63186,9 +63557,6 @@
                   "Value": "HTTPS"
                 }
               },
-              "wam": {
-                "Value": "wam"
-              },
               "wellarchitectedtool": {
                 "Value": "wellarchitectedtool",
                 "endpoint": {
diff --git a/moto/ssm/resources/services.json b/moto/ssm/resources/services.json
index 5235d9592..0cfe4d90d 100644
--- a/moto/ssm/resources/services.json
+++ b/moto/ssm/resources/services.json
@@ -5331,6 +5331,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "ca-west-1": {
+                "Value": "ca-west-1",
+                "endpoint": {
+                  "Value": "athena.ca-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "cn-north-1": {
                 "Value": "cn-north-1",
                 "endpoint": {
@@ -6793,6 +6802,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "ca-west-1": {
+                "Value": "ca-west-1",
+                "endpoint": {
+                  "Value": "backup.ca-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "cn-north-1": {
                 "Value": "cn-north-1",
                 "endpoint": {
@@ -13506,6 +13524,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "eu-central-2": {
+                "Value": "eu-central-2",
+                "endpoint": {
+                  "Value": "cognito-identity.eu-central-2.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "eu-north-1": {
                 "Value": "eu-north-1",
                 "endpoint": {
@@ -13730,6 +13757,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "eu-central-2": {
+                "Value": "eu-central-2",
+                "endpoint": {
+                  "Value": "cognito-idp.eu-central-2.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "eu-north-1": {
                 "Value": "eu-north-1",
                 "endpoint": {
@@ -24907,10 +24943,10 @@
           "firehose": {
             "Value": "firehose",
             "longName": {
-              "Value": "Amazon Kinesis Data Firehose"
+              "Value": "Amazon Data Firehose"
             },
             "marketingHomeURL": {
-              "Value": "https://aws.amazon.com/kinesis/firehose/"
+              "Value": "https://aws.amazon.com/firehose/"
             },
             "regions": {
               "af-south-1": {
@@ -27180,6 +27216,24 @@
                   "Value": "HTTPS"
                 }
               },
+              "cn-north-1": {
+                "Value": "cn-north-1",
+                "endpoint": {
+                  "Value": "fsx.cn-north-1.amazonaws.com.cn"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "cn-northwest-1": {
+                "Value": "cn-northwest-1",
+                "endpoint": {
+                  "Value": "fsx.cn-northwest-1.amazonaws.com.cn"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "eu-central-1": {
                 "Value": "eu-central-1",
                 "endpoint": {
@@ -27189,6 +27243,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "eu-central-2": {
+                "Value": "eu-central-2",
+                "endpoint": {
+                  "Value": "fsx.eu-central-2.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "eu-north-1": {
                 "Value": "eu-north-1",
                 "endpoint": {
@@ -27207,6 +27270,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "eu-south-2": {
+                "Value": "eu-south-2",
+                "endpoint": {
+                  "Value": "fsx.eu-south-2.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "eu-west-1": {
                 "Value": "eu-west-1",
                 "endpoint": {
@@ -27288,6 +27360,24 @@
                   "Value": "HTTPS"
                 }
               },
+              "us-gov-east-1": {
+                "Value": "us-gov-east-1",
+                "endpoint": {
+                  "Value": "fsx.us-gov-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "us-gov-west-1": {
+                "Value": "us-gov-west-1",
+                "endpoint": {
+                  "Value": "fsx.us-gov-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "us-west-1": {
                 "Value": "us-west-1",
                 "endpoint": {
@@ -29741,6 +29831,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "ap-southeast-4": {
+                "Value": "ap-southeast-4",
+                "endpoint": {
+                  "Value": "sso.ap-southeast-4.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "ca-central-1": {
                 "Value": "ca-central-1",
                 "endpoint": {
@@ -34959,6 +35058,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "ca-west-1": {
+                "Value": "ca-west-1",
+                "endpoint": {
+                  "Value": "kinesisanalytics.ca-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "cn-north-1": {
                 "Value": "cn-north-1",
                 "endpoint": {
@@ -42801,6 +42909,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "eu-west-2": {
+                "Value": "eu-west-2",
+                "endpoint": {
+                  "Value": "neptune-graph.eu-west-2.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "us-east-1": {
                 "Value": "us-east-1",
                 "endpoint": {
@@ -57559,6 +57676,24 @@
                   "Value": "HTTPS"
                 }
               },
+              "us-gov-east-1": {
+                "Value": "us-gov-east-1",
+                "endpoint": {
+                  "Value": "signer.us-gov-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "us-gov-west-1": {
+                "Value": "us-gov-west-1",
+                "endpoint": {
+                  "Value": "signer.us-gov-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "us-west-1": {
                 "Value": "us-west-1",
                 "endpoint": {
@@ -59714,6 +59849,15 @@
                   "Value": "HTTPS"
                 }
               },
+              "ap-southeast-4": {
+                "Value": "ap-southeast-4",
+                "endpoint": {
+                  "Value": "oidc.ap-southeast-4.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "ca-central-1": {
                 "Value": "ca-central-1",
                 "endpoint": {
@@ -60817,6 +60961,123 @@
               "Value": "https://aws.amazon.com/premiumsupport/"
             },
             "regions": {
+              "af-south-1": {
+                "Value": "af-south-1",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "ap-east-1": {
+                "Value": "ap-east-1",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "ap-northeast-1": {
+                "Value": "ap-northeast-1",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "ap-northeast-2": {
+                "Value": "ap-northeast-2",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "ap-northeast-3": {
+                "Value": "ap-northeast-3",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "ap-south-1": {
+                "Value": "ap-south-1",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "ap-south-2": {
+                "Value": "ap-south-2",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "ap-southeast-1": {
+                "Value": "ap-southeast-1",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "ap-southeast-2": {
+                "Value": "ap-southeast-2",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "ap-southeast-3": {
+                "Value": "ap-southeast-3",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "ap-southeast-4": {
+                "Value": "ap-southeast-4",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "ca-central-1": {
+                "Value": "ca-central-1",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "ca-west-1": {
+                "Value": "ca-west-1",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "cn-north-1": {
                 "Value": "cn-north-1",
                 "endpoint": {
@@ -60835,8 +61096,107 @@
                   "Value": "HTTPS"
                 }
               },
+              "eu-central-1": {
+                "Value": "eu-central-1",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "eu-central-2": {
+                "Value": "eu-central-2",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "eu-north-1": {
+                "Value": "eu-north-1",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "eu-south-1": {
+                "Value": "eu-south-1",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "eu-south-2": {
+                "Value": "eu-south-2",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "eu-west-1": {
                 "Value": "eu-west-1",
+                "endpoint": {
+                  "Value": "support.eu-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "eu-west-2": {
+                "Value": "eu-west-2",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "eu-west-3": {
+                "Value": "eu-west-3",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "il-central-1": {
+                "Value": "il-central-1",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "me-central-1": {
+                "Value": "me-central-1",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "me-south-1": {
+                "Value": "me-south-1",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "sa-east-1": {
+                "Value": "sa-east-1",
                 "endpoint": {
                   "Value": "support.us-east-1.amazonaws.com"
                 },
@@ -60853,6 +61213,24 @@
                   "Value": "HTTPS"
                 }
               },
+              "us-east-2": {
+                "Value": "us-east-2",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
+              "us-gov-east-1": {
+                "Value": "us-gov-east-1",
+                "endpoint": {
+                  "Value": "support.us-gov-west-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "us-gov-west-1": {
                 "Value": "us-gov-west-1",
                 "endpoint": {
@@ -60862,10 +61240,19 @@
                   "Value": "HTTPS"
                 }
               },
+              "us-west-1": {
+                "Value": "us-west-1",
+                "endpoint": {
+                  "Value": "support.us-east-1.amazonaws.com"
+                },
+                "protocols": {
+                  "Value": "HTTPS"
+                }
+              },
               "us-west-2": {
                 "Value": "us-west-2",
                 "endpoint": {
-                  "Value": "support.us-east-1.amazonaws.com"
+                  "Value": "support.us-west-2.amazonaws.com"
                 },
                 "protocols": {
                   "Value": "HTTPS"
@@ -64733,32 +65120,6 @@
               }
             }
           },
-          "wam": {
-            "Value": "wam",
-            "longName": {
-              "Value": "Amazon WorkSpaces Application Manager"
-            },
-            "marketingHomeURL": {
-              "Value": "https://aws.amazon.com/workspaces/applicationmanager/"
-            },
-            "regions": {
-              "ap-southeast-1": {
-                "Value": "ap-southeast-1"
-              },
-              "ap-southeast-2": {
-                "Value": "ap-southeast-2"
-              },
-              "eu-west-1": {
-                "Value": "eu-west-1"
-              },
-              "us-east-1": {
-                "Value": "us-east-1"
-              },
-              "us-west-2": {
-                "Value": "us-west-2"
-              }
-            }
-          },
           "wellarchitectedtool": {
             "Value": "wellarchitectedtool",
             "longName": {


Test patch:
diff --git a/tests/test_autoscaling/test_autoscaling.py b/tests/test_autoscaling/test_autoscaling.py
index 8136f2727..a052b8640 100644
--- a/tests/test_autoscaling/test_autoscaling.py
+++ b/tests/test_autoscaling/test_autoscaling.py
@@ -1,3 +1,4 @@
+from datetime import datetime
 from uuid import uuid4
 
 import boto3
@@ -1325,3 +1326,28 @@ def test_create_template_with_block_device():
     # Our Ebs-volume
     assert volumes[1]["VolumeType"] == "gp3"
     assert volumes[1]["Size"] == 20
+
+
+@mock_aws
+def test_sets_created_time():
+    mocked_networking = setup_networking()
+    conn = boto3.client("autoscaling", region_name="us-east-1")
+    conn.create_launch_configuration(
+        LaunchConfigurationName="TestLC",
+        ImageId=EXAMPLE_AMI_ID,
+        InstanceType="t2.medium",
+    )
+
+    conn.create_auto_scaling_group(
+        AutoScalingGroupName="TestGroup1",
+        MinSize=1,
+        MaxSize=2,
+        LaunchConfigurationName="TestLC",
+        VPCZoneIdentifier=mocked_networking["subnet1"],
+    )
+
+    asgs = conn.describe_auto_scaling_groups()["AutoScalingGroups"]
+    assert len(asgs) == 1
+    assert asgs[0]["CreatedTime"] != datetime.strptime(
+        "2013-05-06T17:47:15.107Z", "%Y-%m-%dT%H:%M:%S.%f%z"
+    )
diff --git a/tests/test_dynamodb/__init__.py b/tests/test_dynamodb/__init__.py
index fb3729acd..3c8492eba 100644
--- a/tests/test_dynamodb/__init__.py
+++ b/tests/test_dynamodb/__init__.py
@@ -7,7 +7,7 @@ import boto3
 from moto import mock_aws
 
 
-def dynamodb_aws_verified(create_table: bool = True):
+def dynamodb_aws_verified(create_table: bool = True, add_range: bool = False):
     """
     Function that is verified to work against AWS.
     Can be run against AWS at any time by setting:
@@ -46,10 +46,15 @@ def dynamodb_aws_verified(create_table: bool = True):
         def create_table_and_test(table_name):
             client = boto3.client("dynamodb", region_name="us-east-1")
 
+            schema = [{"AttributeName": "pk", "KeyType": "HASH"}]
+            defs = [{"AttributeName": "pk", "AttributeType": "S"}]
+            if add_range:
+                schema.append({"AttributeName": "sk", "KeyType": "RANGE"})
+                defs.append({"AttributeName": "sk", "AttributeType": "S"})
             client.create_table(
                 TableName=table_name,
-                KeySchema=[{"AttributeName": "pk", "KeyType": "HASH"}],
-                AttributeDefinitions=[{"AttributeName": "pk", "AttributeType": "S"}],
+                KeySchema=schema,
+                AttributeDefinitions=defs,
                 ProvisionedThroughput={"ReadCapacityUnits": 1, "WriteCapacityUnits": 5},
                 Tags=[{"Key": "environment", "Value": "moto_tests"}],
             )
diff --git a/tests/test_dynamodb/test_dynamodb.py b/tests/test_dynamodb/test_dynamodb.py
index 8feeb8fa2..fbb781ae0 100644
--- a/tests/test_dynamodb/test_dynamodb.py
+++ b/tests/test_dynamodb/test_dynamodb.py
@@ -1,3 +1,4 @@
+import copy
 import re
 import uuid
 from datetime import datetime
@@ -5957,3 +5958,125 @@ def test_update_item_with_global_secondary_index():
                 "One or more parameter values were invalid: Type mismatch"
                 in err["Message"]
             )
+
+
+@pytest.mark.aws_verified
+@dynamodb_aws_verified(add_range=True)
+def test_query_with_unknown_last_evaluated_key(table_name=None):
+    client = boto3.client("dynamodb", region_name="us-east-1")
+
+    for i in range(10):
+        client.put_item(
+            TableName=table_name,
+            Item={
+                "pk": {"S": "hash_value"},
+                "sk": {"S": f"range_value{i}"},
+            },
+        )
+
+    p1 = client.query(
+        TableName=table_name,
+        KeyConditionExpression="#h = :h",
+        ExpressionAttributeNames={"#h": "pk"},
+        ExpressionAttributeValues={":h": {"S": "hash_value"}},
+        Limit=1,
+    )
+    assert p1["Items"] == [{"pk": {"S": "hash_value"}, "sk": {"S": "range_value0"}}]
+
+    # Using the Exact ExclusiveStartKey provided
+    p2 = client.query(
+        TableName=table_name,
+        KeyConditionExpression="#h = :h",
+        ExpressionAttributeNames={"#h": "pk"},
+        ExpressionAttributeValues={":h": {"S": "hash_value"}},
+        Limit=1,
+        ExclusiveStartKey=p1["LastEvaluatedKey"],
+    )
+    assert p2["Items"] == [{"pk": {"S": "hash_value"}, "sk": {"S": "range_value1"}}]
+
+    # We can change ExclusiveStartKey
+    # It doesn't need to match - it just needs to be >= page1, but < page1
+    different_key = copy.copy(p1["LastEvaluatedKey"])
+    different_key["sk"]["S"] = different_key["sk"]["S"] + "0"
+    p3 = client.query(
+        TableName=table_name,
+        KeyConditionExpression="#h = :h",
+        ExpressionAttributeNames={"#h": "pk"},
+        ExpressionAttributeValues={":h": {"S": "hash_value"}},
+        Limit=1,
+        ExclusiveStartKey=different_key,
+    )
+    assert p3["Items"] == [{"pk": {"S": "hash_value"}, "sk": {"S": "range_value1"}}]
+
+    # Sanity check - increasing the sk to something much greater will result in a different outcome
+    different_key["sk"]["S"] = "range_value500"
+    p4 = client.query(
+        TableName=table_name,
+        KeyConditionExpression="#h = :h",
+        ExpressionAttributeNames={"#h": "pk"},
+        ExpressionAttributeValues={":h": {"S": "hash_value"}},
+        Limit=1,
+        ExclusiveStartKey=different_key,
+    )
+    assert p4["Items"] == [{"pk": {"S": "hash_value"}, "sk": {"S": "range_value6"}}]
+
+
+@pytest.mark.aws_verified
+@dynamodb_aws_verified(add_range=True)
+def test_scan_with_unknown_last_evaluated_key(table_name=None):
+    client = boto3.client("dynamodb", region_name="us-east-1")
+
+    for i in range(10):
+        client.put_item(
+            TableName=table_name,
+            Item={
+                "pk": {"S": "hash_value"},
+                "sk": {"S": f"range_value{i}"},
+            },
+        )
+
+    p1 = client.scan(
+        TableName=table_name,
+        FilterExpression="#h = :h",
+        ExpressionAttributeNames={"#h": "pk"},
+        ExpressionAttributeValues={":h": {"S": "hash_value"}},
+        Limit=1,
+    )
+    assert p1["Items"] == [{"pk": {"S": "hash_value"}, "sk": {"S": "range_value0"}}]
+
+    # Using the Exact ExclusiveStartKey provided
+    p2 = client.scan(
+        TableName=table_name,
+        FilterExpression="#h = :h",
+        ExpressionAttributeNames={"#h": "pk"},
+        ExpressionAttributeValues={":h": {"S": "hash_value"}},
+        Limit=1,
+        ExclusiveStartKey=p1["LastEvaluatedKey"],
+    )
+    assert p2["Items"] == [{"pk": {"S": "hash_value"}, "sk": {"S": "range_value1"}}]
+
+    # We can change ExclusiveStartKey
+    # It doesn't need to match - it just needs to be >= page1, but < page1
+    different_key = copy.copy(p1["LastEvaluatedKey"])
+    different_key["sk"]["S"] = different_key["sk"]["S"] + "0"
+    p3 = client.scan(
+        TableName=table_name,
+        FilterExpression="#h = :h",
+        ExpressionAttributeNames={"#h": "pk"},
+        ExpressionAttributeValues={":h": {"S": "hash_value"}},
+        Limit=1,
+        ExclusiveStartKey=different_key,
+    )
+    assert p3["Items"] == [{"pk": {"S": "hash_value"}, "sk": {"S": "range_value1"}}]
+
+    # Sanity check - increasing the sk to something much greater will result in a different outcome
+    different_key["sk"]["S"] = "range_value500"
+    p4 = client.scan(
+        TableName=table_name,
+        FilterExpression="#h = :h",
+        ExpressionAttributeNames={"#h": "pk"},
+        ExpressionAttributeValues={":h": {"S": "hash_value"}},
+        Limit=1,
+        ExclusiveStartKey=different_key,
+    )
+    assert p4["Items"] == [{"pk": {"S": "hash_value"}, "sk": {"S": "range_value6"}}]
diff --git a/tests/test_dynamodb/test_dynamodb_table_without_range_key.py b/tests/test_dynamodb/test_dynamodb_table_without_range_key.py
index ac8afc9dc..bff168cc8 100644
--- a/tests/test_dynamodb/test_dynamodb_table_without_range_key.py
+++ b/tests/test_dynamodb/test_dynamodb_table_without_range_key.py
@@ -8,6 +8,8 @@ from botocore.exceptions import ClientError
 from moto import mock_aws
 from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
 
+from . import dynamodb_aws_verified
+
 
 @mock_aws
 def test_create_table():
@@ -512,29 +514,26 @@ def test_update_settype_item_with_conditions():
     assert returned_item["Item"]["foo"] == set(["baz"])
 
 
-@mock_aws
-def test_scan_pagination():
-    table = _create_user_table()
-
+@pytest.mark.aws_verified
+@dynamodb_aws_verified()
+def test_scan_pagination(table_name=None):
+    table = boto3.resource("dynamodb", "us-east-1").Table(table_name)
     expected_usernames = [f"user{i}" for i in range(10)]
     for u in expected_usernames:
-        table.put_item(Item={"username": u})
+        table.put_item(Item={"pk": u})
 
     page1 = table.scan(Limit=6)
     assert page1["Count"] == 6
     assert len(page1["Items"]) == 6
-    page1_results = set([r["username"] for r in page1["Items"]])
-    assert page1_results == {"user0", "user3", "user1", "user2", "user5", "user4"}
+    page1_results = [r["pk"] for r in page1["Items"]]
 
     page2 = table.scan(Limit=6, ExclusiveStartKey=page1["LastEvaluatedKey"])
     assert page2["Count"] == 4
     assert len(page2["Items"]) == 4
     assert "LastEvaluatedKey" not in page2
-    page2_results = set([r["username"] for r in page2["Items"]])
-    assert page2_results == {"user6", "user7", "user8", "user9"}
+    page2_results = [r["pk"] for r in page2["Items"]]
 
-    results = page1["Items"] + page2["Items"]
-    usernames = set([r["username"] for r in results])
+    usernames = set(page1_results + page2_results)
     assert usernames == set(expected_usernames)
 
 
diff --git a/tests/test_resiliencehub/test_resiliencyhub_resources.py b/tests/test_resiliencehub/test_resiliencyhub_resources.py
new file mode 100644
index 000000000..b3d05b23d
--- /dev/null
+++ b/tests/test_resiliencehub/test_resiliencyhub_resources.py
@@ -0,0 +1,162 @@
+import boto3
+
+from moto import mock_aws
+
+
+@mock_aws
+def test_import_resources_to_draft_app_version():
+    client = boto3.client("resiliencehub", region_name="us-east-2")
+    app_arn = client.create_app(name="myapp")["app"]["appArn"]
+
+    components = client.list_app_version_app_components(
+        appArn=app_arn, appVersion="draft"
+    )
+    assert components["appArn"] == app_arn
+    assert components["appComponents"] == []
+    assert components["appVersion"] == "draft"
+
+    resp = client.import_resources_to_draft_app_version(
+        appArn=app_arn,
+        eksSources=[{"eksClusterArn": "some-arn", "namespaces": ["eks/ns/1"]}],
+        importStrategy="AddOnly",
+        sourceArns=["sarn1", "sarn2"],
+        terraformSources=[{"s3StateFileUrl": "tf://url"}],
+    )
+    assert resp["appArn"] == app_arn
+    assert resp["eksSources"] == [
+        {"eksClusterArn": "some-arn", "namespaces": ["eks/ns/1"]}
+    ]
+    assert resp["sourceArns"] == ["sarn1", "sarn2"]
+    assert resp["status"] == "Pending"
+    assert resp["terraformSources"] == [{"s3StateFileUrl": "tf://url"}]
+
+    components = client.list_app_version_app_components(
+        appArn=app_arn, appVersion="draft"
+    )["appComponents"]
+    assert {
+        "id": "appcommon",
+        "name": "appcommon",
+        "type": "AWS::ResilienceHub::AppCommonAppComponent",
+    } in components
+
+
+@mock_aws
+def test_create_app_version_app_component():
+    client = boto3.client("resiliencehub", region_name="us-east-2")
+    app_arn = client.create_app(name="myapp")["app"]["appArn"]
+    component = client.create_app_version_app_component(
+        appArn=app_arn,
+        name="my_databases",
+        type="AWS::ResilienceHub::DatabaseAppComponent",
+    )
+    assert component["appArn"] == app_arn
+    assert component["appVersion"] == "draft"
+    assert component["appComponent"]["id"] == "my_databases"
+    assert component["appComponent"]["name"] == "my_databases"
+    assert (
+        component["appComponent"]["type"] == "AWS::ResilienceHub::DatabaseAppComponent"
+    )
+
+    components = client.list_app_version_app_components(
+        appArn=app_arn, appVersion="draft"
+    )["appComponents"]
+    assert components == [
+        {
+            "id": "my_databases",
+            "name": "my_databases",
+            "type": "AWS::ResilienceHub::DatabaseAppComponent",
+        }
+    ]
+
+
+@mock_aws
+def test_create_app_version_resource():
+    client = boto3.client("resiliencehub", region_name="us-east-2")
+    app_arn = client.create_app(name="myapp")["app"]["appArn"]
+
+    component = client.create_app_version_app_component(
+        appArn=app_arn,
+        name="my_databases",
+        type="AWS::ResilienceHub::DatabaseAppComponent",
+    )["appComponent"]
+
+    resp = client.create_app_version_resource(
+        appArn=app_arn,
+        appComponents=["my_databases"],
+        logicalResourceId={
+            "identifier": "myres",
+        },
+        physicalResourceId="myphys",
+        resourceType="AWS::Lambda::Function",
+    )
+    assert resp["appArn"] == app_arn
+    assert resp["appVersion"] == "draft"
+    assert resp["physicalResource"]["appComponents"] == [component]
+    assert resp["physicalResource"]["logicalResourceId"] == {"identifier": "myres"}
+    assert resp["physicalResource"]["physicalResourceId"]["identifier"] == "myphys"
+    assert resp["physicalResource"]["resourceName"] == "myres"
+    assert resp["physicalResource"]["resourceType"] == "AWS::Lambda::Function"
+
+    resources = client.list_app_version_resources(appArn=app_arn, appVersion="draft")
+    assert resources["physicalResources"] == [resp["physicalResource"]]
+
+
+@mock_aws
+def test_create_app_version_resource_with_unknown_component():
+    client = boto3.client("resiliencehub", region_name="us-east-2")
+    app_arn = client.create_app(name="myapp")["app"]["appArn"]
+
+    # Not sure how AWS behaves, when providing an unknown appComponent
+    # But let's try to be flexible in what we accept
+    resp = client.create_app_version_resource(
+        appArn=app_arn,
+        appComponents=["unknown"],
+        logicalResourceId={
+            "identifier": "myres",
+        },
+        physicalResourceId="myphys",
+        resourceType="AWS::Lambda::Function",
+    )
+    assert resp["physicalResource"]["appComponents"] == []
+
+
+@mock_aws
+def test_publish():
+    client = boto3.client("resiliencehub", region_name="us-east-2")
+    app_arn = client.create_app(name="myapp")["app"]["appArn"]
+
+    versions = client.list_app_versions(appArn=app_arn)["appVersions"]
+    assert len(versions) == 1
+    assert versions[0]["appVersion"] == "draft"
+    assert versions[0]["creationTime"]
+    assert versions[0]["identifier"] == 0
+
+    client.import_resources_to_draft_app_version(
+        appArn=app_arn,
+        eksSources=[{"eksClusterArn": "some-arn", "namespaces": ["eks/ns/1"]}],
+        importStrategy="AddOnly",
+        sourceArns=["sarn1", "sarn2"],
+        terraformSources=[{"s3StateFileUrl": "tf://url"}],
+    )
+
+    publish = client.publish_app_version(appArn=app_arn, versionName="v1")
+    assert publish["appArn"] == app_arn
+    assert publish["appVersion"] == "release"
+    assert publish["identifier"] == 1
+    assert publish["versionName"] == "v1"
+
+    versions = client.list_app_versions(appArn=app_arn)["appVersions"]
+    assert len(versions) == 2
+    assert versions[1]["appVersion"] == "release"
+    assert versions[1]["identifier"] == 1
+    assert versions[1]["versionName"] == "v1"
+
+    client.publish_app_version(appArn=app_arn, versionName="v2")
+
+    versions = client.list_app_versions(appArn=app_arn)["appVersions"]
+    assert len(versions) == 3
+    for v in versions:
+        del v["creationTime"]
+
+    assert {"appVersion": "release", "identifier": 2, "versionName": "v2"} in versions
+    assert {"appVersion": "1", "identifier": 1, "versionName": "v1"} in versions