Skip to content

Commit 230f745

Browse files
authored
Adding metadata property for unsupported connector profile (#2879)
Co-authored-by: Gavin Zhang <[email protected]>
1 parent 633ce6a commit 230f745

File tree

4 files changed

+94
-2
lines changed

4 files changed

+94
-2
lines changed

samtranslator/model/connector/connector.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
],
2121
)
2222

23+
UNSUPPORTED_CONNECTOR_PROFILE_TYPE = "UNSUPPORTED_CONNECTOR_PROFILE_TYPE"
24+
2325

2426
class ConnectorResourceError(Exception):
2527
"""

samtranslator/model/exceptions.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from abc import ABC, abstractmethod
2+
from collections import defaultdict
23
from enum import Enum
3-
from typing import List, Optional, Sequence, Union
4+
from typing import Any, Dict, List, Optional, Sequence, Union
45

56

67
class ExpectedType(Enum):
@@ -16,12 +17,17 @@ class ExceptionWithMessage(ABC, Exception):
1617
def message(self) -> str:
1718
"""Return the exception message."""
1819

20+
@property
21+
def metadata(self) -> Optional[Dict[str, Any]]:
22+
"""Return the exception metadata."""
23+
1924

2025
class InvalidDocumentException(ExceptionWithMessage):
2126
"""Exception raised when the given document is invalid and cannot be transformed.
2227
2328
Attributes:
2429
message -- explanation of the error
30+
metadata -- a dictionary of metadata (key, value pair)
2531
causes -- list of errors which caused this document to be invalid
2632
"""
2733

@@ -37,6 +43,17 @@ def message(self) -> str:
3743
len(self.causes)
3844
)
3945

46+
@property
47+
def metadata(self) -> Dict[str, List[Any]]:
48+
# Merge metadata in each exception to one single metadata dictionary
49+
metadata_dict = defaultdict(list)
50+
for cause in self.causes:
51+
if not cause.metadata:
52+
continue
53+
for k, v in cause.metadata.items():
54+
metadata_dict[k].append(v)
55+
return metadata_dict
56+
4057
@property
4158
def causes(self) -> Sequence[ExceptionWithMessage]:
4259
return self._causes
@@ -86,9 +103,12 @@ class InvalidResourceException(ExceptionWithMessage):
86103
message -- explanation of the error
87104
"""
88105

89-
def __init__(self, logical_id: Union[str, List[str]], message: str) -> None:
106+
def __init__(
107+
self, logical_id: Union[str, List[str]], message: str, metadata: Optional[Dict[str, Any]] = None
108+
) -> None:
90109
self._logical_id = logical_id
91110
self._message = message
111+
self._metadata = metadata
92112

93113
def __lt__(self, other): # type: ignore[no-untyped-def]
94114
return self._logical_id < other._logical_id
@@ -97,6 +117,10 @@ def __lt__(self, other): # type: ignore[no-untyped-def]
97117
def message(self) -> str:
98118
return "Resource with id [{}] is invalid. {}".format(self._logical_id, self._message)
99119

120+
@property
121+
def metadata(self) -> Optional[Dict[str, Any]]:
122+
return self._metadata
123+
100124

101125
class InvalidResourcePropertyTypeException(InvalidResourceException):
102126
def __init__(

samtranslator/model/sam_resources.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from samtranslator.model.architecture import ARM64, X86_64
3333
from samtranslator.model.cloudformation import NestedStack
3434
from samtranslator.model.connector.connector import (
35+
UNSUPPORTED_CONNECTOR_PROFILE_TYPE,
3536
ConnectorResourceError,
3637
ConnectorResourceReference,
3738
add_depends_on,
@@ -1861,6 +1862,7 @@ def generate_resources(
18611862
raise InvalidResourceException(
18621863
self.logical_id,
18631864
f"Unable to create connector from {source.resource_type} to {destination.resource_type}; it's not supported or the template is invalid.",
1865+
{UNSUPPORTED_CONNECTOR_PROFILE_TYPE: {source.resource_type: destination.resource_type}},
18641866
)
18651867

18661868
# removing duplicate permissions

tests/model/test_exceptions.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from unittest import TestCase
2+
3+
from samtranslator.model.exceptions import (
4+
DuplicateLogicalIdException,
5+
InvalidResourceException,
6+
InvalidDocumentException,
7+
InvalidTemplateException,
8+
InvalidEventException,
9+
)
10+
11+
12+
class TestExceptions(TestCase):
13+
def setUp(self) -> None:
14+
self.invalid_template = InvalidTemplateException("foo")
15+
self.duplicate_id = DuplicateLogicalIdException("foo", "bar", "type")
16+
self.invalid_resource = InvalidResourceException("foo", "bar")
17+
self.invalid_event = InvalidEventException("foo", "bar")
18+
self.invalid_resource_with_metadata = InvalidResourceException("foo-bar", "foo", {"hello": "world"})
19+
20+
def test_invalid_template(self):
21+
self.assertEqual(self.invalid_template.metadata, None)
22+
self.assertIn("Structure of the SAM template is invalid", self.invalid_template.message)
23+
24+
def test_duplicate_id(self):
25+
self.assertEqual(self.duplicate_id.metadata, None)
26+
self.assertIn("Transforming resource with id", self.duplicate_id.message)
27+
28+
def test_invalid_resource_without_metadata(self):
29+
self.assertEqual(self.invalid_resource.metadata, None)
30+
self.assertIn("Resource with id [foo] is invalid", self.invalid_resource.message)
31+
32+
def test_invalid_resource_with_metadata(self):
33+
self.assertEqual(self.invalid_resource_with_metadata.metadata, {"hello": "world"})
34+
self.assertIn("Resource with id [foo-bar] is invalid", self.invalid_resource_with_metadata.message)
35+
36+
def test_invalid_event(self):
37+
self.assertEqual(self.invalid_event.metadata, None)
38+
self.assertIn("Event with id [foo] is invalid.", self.invalid_event.message)
39+
40+
def test_invalid_document_exceptions(self):
41+
unsupported_connector_profile = InvalidResourceException("hello", "world", {"KEY": {"C": "D"}})
42+
unsupported_connector_profile2 = InvalidResourceException("foobar", "bar", {"KEY": {"A": "B"}})
43+
self.assertEqual(unsupported_connector_profile.metadata, {"KEY": {"C": "D"}})
44+
self.assertEqual(unsupported_connector_profile2.metadata, {"KEY": {"A": "B"}})
45+
46+
invalid_document_exception = InvalidDocumentException(
47+
[
48+
self.invalid_template,
49+
self.duplicate_id,
50+
self.invalid_resource,
51+
self.invalid_event,
52+
self.invalid_resource_with_metadata,
53+
unsupported_connector_profile,
54+
unsupported_connector_profile2,
55+
]
56+
)
57+
self.assertEqual(
58+
"Invalid Serverless Application Specification document. Number of errors found: 7.",
59+
invalid_document_exception.message,
60+
)
61+
self.assertEqual(
62+
invalid_document_exception.metadata,
63+
{"hello": ["world"], "KEY": [{"C": "D"}, {"A": "B"}]},
64+
)

0 commit comments

Comments
 (0)