Repository: getmoto/moto
Pull request #5995 (2023-02-27 20:08:15)

Techdebt: SSM: Specific param may not exist on the first page


Patch:
diff --git a/moto/dynamodb/exceptions.py b/moto/dynamodb/exceptions.py
index 87642779a..017c35b7c 100644
--- a/moto/dynamodb/exceptions.py
+++ b/moto/dynamodb/exceptions.py
@@ -4,12 +4,15 @@ from moto.core.exceptions import JsonRESTError
 from moto.dynamodb.limits import HASH_KEY_MAX_LENGTH, RANGE_KEY_MAX_LENGTH
 
 
+ERROR_TYPE_PREFIX = "com.amazonaws.dynamodb.v20120810#"
+
+
 class DynamodbException(JsonRESTError):
     pass
 
 
 class MockValidationException(DynamodbException):
-    error_type = "com.amazonaws.dynamodb.v20111205#ValidationException"
+    error_type = ERROR_TYPE_PREFIX + "ValidationException"
 
     def __init__(self, message: str):
         super().__init__(MockValidationException.error_type, message=message)
@@ -190,7 +193,7 @@ class IncorrectDataType(MockValidationException):
 
 
 class ConditionalCheckFailed(DynamodbException):
-    error_type = "com.amazonaws.dynamodb.v20111205#ConditionalCheckFailedException"
+    error_type = ERROR_TYPE_PREFIX + "ConditionalCheckFailedException"
 
     def __init__(self, msg: Optional[str] = None):
         super().__init__(
@@ -279,44 +282,47 @@ class TooManyAddClauses(InvalidUpdateExpression):
 
 
 class ResourceNotFoundException(JsonRESTError):
-    def __init__(self, msg: Optional[str] = None):
-        err = "com.amazonaws.dynamodb.v20111205#ResourceNotFoundException"
-        super().__init__(err, msg or "Requested resource not found")
+    def __init__(self, msg: Optional[str] = None, table_name: Optional[str] = None):
+        err = ERROR_TYPE_PREFIX + "ResourceNotFoundException"
+        default_msg = "Requested resource not found"
+        if table_name is not None:
+            default_msg += f": Table: {table_name} not found"
+        super().__init__(err, msg or default_msg)
 
 
 class TableNotFoundException(JsonRESTError):
     def __init__(self, name: str):
-        err = "com.amazonaws.dynamodb.v20111205#TableNotFoundException"
+        err = ERROR_TYPE_PREFIX + "TableNotFoundException"
         super().__init__(err, f"Table not found: {name}")
 
 
 class SourceTableNotFoundException(JsonRESTError):
     def __init__(self, source_table_name: str):
-        er = "com.amazonaws.dynamodb.v20111205#SourceTableNotFoundException"
+        er = ERROR_TYPE_PREFIX + "SourceTableNotFoundException"
         super().__init__(er, f"Source table not found: {source_table_name}")
 
 
 class BackupNotFoundException(JsonRESTError):
     def __init__(self, backup_arn: str):
-        er = "com.amazonaws.dynamodb.v20111205#BackupNotFoundException"
+        er = ERROR_TYPE_PREFIX + "BackupNotFoundException"
         super().__init__(er, f"Backup not found: {backup_arn}")
 
 
 class TableAlreadyExistsException(JsonRESTError):
     def __init__(self, target_table_name: str):
-        er = "com.amazonaws.dynamodb.v20111205#TableAlreadyExistsException"
+        er = ERROR_TYPE_PREFIX + "TableAlreadyExistsException"
         super().__init__(er, f"Table already exists: {target_table_name}")
 
 
 class ResourceInUseException(JsonRESTError):
     def __init__(self) -> None:
-        er = "com.amazonaws.dynamodb.v20111205#ResourceInUseException"
+        er = ERROR_TYPE_PREFIX + "ResourceInUseException"
         super().__init__(er, "Resource in use")
 
 
 class StreamAlreadyEnabledException(JsonRESTError):
     def __init__(self) -> None:
-        er = "com.amazonaws.dynamodb.v20111205#ResourceInUseException"
+        er = ERROR_TYPE_PREFIX + "ResourceInUseException"
         super().__init__(er, "Cannot enable stream")
 
 
diff --git a/moto/dynamodb/models/__init__.py b/moto/dynamodb/models/__init__.py
index 7b03cb1ba..333b1ed63 100644
--- a/moto/dynamodb/models/__init__.py
+++ b/moto/dynamodb/models/__init__.py
@@ -123,8 +123,10 @@ class DynamoDBBackend(BaseBackend):
         return tables, None
 
     def describe_table(self, name: str) -> Dict[str, Any]:
-        table = self.get_table(name)
-        return table.describe(base_key="Table")
+        # We can't use get_table() here, because the error message is slightly different for this operation
+        if name not in self.tables:
+            raise ResourceNotFoundException(table_name=name)
+        return self.tables[name].describe(base_key="Table")
 
     def update_table(
         self,


Test patch:
diff --git a/tests/test_dynamodb/test_dynamodb.py b/tests/test_dynamodb/test_dynamodb.py
index 2146184dc..d7b19810c 100644
--- a/tests/test_dynamodb/test_dynamodb.py
+++ b/tests/test_dynamodb/test_dynamodb.py
@@ -66,7 +66,9 @@ def test_describe_missing_table_boto3():
         conn.describe_table(TableName="messages")
     ex.value.response["Error"]["Code"].should.equal("ResourceNotFoundException")
     ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
-    ex.value.response["Error"]["Message"].should.equal("Requested resource not found")
+    ex.value.response["Error"]["Message"].should.equal(
+        "Requested resource not found: Table: messages not found"
+    )
 
 
 @mock_dynamodb
diff --git a/tests/test_dynamodb/test_server.py b/tests/test_dynamodb/test_server.py
index 9afa08076..ae6ddc88f 100644
--- a/tests/test_dynamodb/test_server.py
+++ b/tests/test_dynamodb/test_server.py
@@ -1,5 +1,6 @@
+import json
 import sure  # noqa # pylint: disable=unused-import
-
+from moto import mock_dynamodb
 import moto.server as server
 
 """
@@ -7,6 +8,7 @@ Test the different server responses
 """
 
 
+@mock_dynamodb
 def test_table_list():
     backend = server.create_backend_app("dynamodb")
     test_client = backend.test_client()
@@ -17,3 +19,18 @@ def test_table_list():
     res = test_client.get("/", headers=headers)
     res.data.should.contain(b"TableNames")
     res.headers.should.have.key("X-Amz-Crc32")
+
+    headers = {"X-Amz-Target": "DynamoDB_20120810.DescribeTable"}
+    res = test_client.post(
+        "/", headers=headers, data=json.dumps({"TableName": "test-table2"})
+    )
+    res.headers.should.have.key("X-Amzn-ErrorType").equals(
+        "com.amazonaws.dynamodb.v20120810#ResourceNotFoundException"
+    )
+    body = json.loads(res.data.decode("utf-8"))
+    body.should.equal(
+        {
+            "__type": "com.amazonaws.dynamodb.v20120810#ResourceNotFoundException",
+            "message": "Requested resource not found: Table: test-table2 not found",
+        }
+    )
diff --git a/tests/test_ssm/test_ssm_default_amis.py b/tests/test_ssm/test_ssm_default_amis.py
index 45cffcc1d..1ee66c574 100644
--- a/tests/test_ssm/test_ssm_default_amis.py
+++ b/tests/test_ssm/test_ssm_default_amis.py
@@ -14,11 +14,12 @@ def test_ssm_get_latest_ami_by_path():
     params = client.get_parameters_by_path(Path=path)["Parameters"]
     params.should.have.length_of(10)
 
-    ami = [p for p in params if p["Name"] == test_ami][0]
-    ami["Type"].should.equal("String")
-    ami["Version"].should.equal(18)
-    ami["Value"].should.equal("ami-0f4e67e32313f0d0e")
-    ami.should.have.key("LastModifiedDate")
+    assert all(
+        [p["Name"].startswith("/aws/service/ami-amazon-linux-latest") for p in params]
+    )
+    assert all([p["Type"] == "String" for p in params])
+    assert all([p["DataType"] == "text" for p in params])
+    assert all([p["ARN"].startswith("arn:aws:ssm:us-west-1") for p in params])
 
 
 @mock_ssm