Repository: getmoto/moto
Pull request #8431 (2024-12-23 09:13:48)

DSQL: implement get_cluster()
This PR is part of https://github.com/getmoto/moto/issues/8413

add DSQL get_cluster() implementation.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/getmoto/moto/pull/8431?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 94.60%. Comparing base [(`1e4364d`)](https://app.codecov.io/gh/getmoto/moto/commit/1e4364de29cb9d1855ab7a940f105705888f1f77?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto) to head [(`e7996c0`)](https://app.codecov.io/gh/getmoto/moto/commit/e7996c0d8fef894f007453d1e997c00faa5a44ea?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getmoto).

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


```diff
@@           Coverage Diff           @@
##           master    #8431   +/-   ##
=======================================
  Coverage   94.60%   94.60%           
=======================================
  Files        1167     1168    +1     
  Lines      101685   101701   +16     
=======================================
+ Hits        96198    96214   +16     
  Misses       5487     5487           
```

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

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

</details>

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


Patch:
diff --git a/moto/dsql/exceptions.py b/moto/dsql/exceptions.py
index 69cbb6b2e..6a9d8bcd0 100644
--- a/moto/dsql/exceptions.py
+++ b/moto/dsql/exceptions.py
@@ -1,1 +1,12 @@
 """Exceptions raised by the dsql service."""
+
+from moto.core.exceptions import JsonRESTError
+
+
+class ValidationException(JsonRESTError):
+    """Tag validation failed."""
+
+    code = 400
+
+    def __init__(self, message: str):
+        super().__init__("ValidationException", message)
diff --git a/moto/dsql/models.py b/moto/dsql/models.py
index 64124fe4d..fb937a40a 100644
--- a/moto/dsql/models.py
+++ b/moto/dsql/models.py
@@ -10,6 +10,8 @@ from moto.moto_api._internal import mock_random
 from moto.moto_api._internal.managed_state_model import ManagedState
 from moto.utilities.utils import get_partition
 
+from .exceptions import ValidationException
+
 
 class Cluster(BaseModel, ManagedState):
     """Model for an AuroraDSQL cluster."""
@@ -68,6 +70,17 @@ class AuroraDSQLBackend(BaseBackend):
             tags,
             client_token,
         )
+        self.clusters[cluster.identifier] = cluster
+        return cluster
+
+    def get_cluster(
+        self,
+        identifier: str,
+    ) -> Cluster:
+        cluster = self.clusters.get(identifier)
+        if cluster is None:
+            raise ValidationException("invalid Cluster Id")
+
         return cluster
 
 
diff --git a/moto/dsql/responses.py b/moto/dsql/responses.py
index 3e3f23198..cde9965d9 100644
--- a/moto/dsql/responses.py
+++ b/moto/dsql/responses.py
@@ -30,3 +30,9 @@ class AuroraDSQLResponse(BaseResponse):
         )
 
         return json.dumps(dict(cluster.to_dict()))
+
+    def get_cluster(self) -> str:
+        identifier = self.path.split("/")[-1]
+        cluster = self.dsql_backend.get_cluster(identifier=identifier)
+
+        return json.dumps(dict(cluster.to_dict()))
diff --git a/moto/dsql/urls.py b/moto/dsql/urls.py
index 8fbbf12ff..4c15cdde4 100644
--- a/moto/dsql/urls.py
+++ b/moto/dsql/urls.py
@@ -8,4 +8,5 @@ url_bases = [
 
 url_paths = {
     "{0}/cluster$": AuroraDSQLResponse.dispatch,
+    "{0}/cluster/(?P<identifier>[^/]+)$": AuroraDSQLResponse.dispatch,
 }
diff --git a/setup.cfg b/setup.cfg
index 086c4acbc..1952101b0 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,7 @@
 [metadata]
 name = moto
 version = 5.0.25.dev
+description = A library that allows you to easily mock out tests based on AWS infrastructure
 long_description = file:README.md
 long_description_content_type = text/markdown
 author = Steve Pulec


Test patch:
diff --git a/tests/test_dsql/test_dsql.py b/tests/test_dsql/test_dsql.py
index 7bfdd95f6..9d0e438e5 100644
--- a/tests/test_dsql/test_dsql.py
+++ b/tests/test_dsql/test_dsql.py
@@ -3,15 +3,18 @@
 from datetime import datetime
 
 import boto3
+from botocore.exceptions import ClientError
 from dateutil.tz import tzutc
 from freezegun import freeze_time
 
 from moto import mock_aws, settings
 
+TEST_REGION = "us-east-1"
+
 
 @mock_aws
 def test_create_cluster():
-    client = boto3.client("dsql", region_name="us-east-1")
+    client = boto3.client("dsql", region_name=TEST_REGION)
     with freeze_time("2024-12-22 12:34:00"):
         resp = client.create_cluster()
 
@@ -22,3 +25,37 @@ def test_create_cluster():
     assert resp["status"] == "CREATING"
     if not settings.TEST_SERVER_MODE:
         assert resp["creationTime"] == datetime(2024, 12, 22, 12, 34, tzinfo=tzutc())
+
+
+@mock_aws
+def test_get_invalid_cluster():
+    client = boto3.client("dsql", region_name=TEST_REGION)
+
+    try:
+        client.get_cluster(identifier="invalid")
+    except ClientError as err:
+        assert err.response["Error"]["Code"] == "ValidationException"
+        assert err.response["Error"]["Message"] == "invalid Cluster Id"
+
+
+@mock_aws
+def test_get_cluster():
+    client = boto3.client("dsql", region_name=TEST_REGION)
+    with freeze_time("2024-12-22 12:34:00"):
+        resp = client.create_cluster()
+
+    identifier = resp["identifier"]
+
+    get_resp = client.get_cluster(identifier=identifier)
+
+    # TODO Add `witnessRegion` and `linkedClusterArns` when implement create-multi-region-clusters
+    assert get_resp["identifier"] == identifier
+    assert (
+        get_resp["arn"] == f"arn:aws:dsql:us-east-1:123456789012:cluster/{identifier}"
+    )
+    assert get_resp["deletionProtectionEnabled"] is True
+    assert get_resp["status"] == "CREATING"
+    if not settings.TEST_SERVER_MODE:
+        assert get_resp["creationTime"] == datetime(
+            2024, 12, 22, 12, 34, tzinfo=tzutc()
+        )