Skip to content

Commit

Permalink
Adding metadata property for unsupported connector profile (#2879)
Browse files Browse the repository at this point in the history
Co-authored-by: Gavin Zhang <yuanhaoz@amazon.com>
  • Loading branch information
GavinZZ and GavinZZ authored Feb 9, 2023
1 parent 633ce6a commit 230f745
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 2 deletions.
2 changes: 2 additions & 0 deletions samtranslator/model/connector/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
],
)

UNSUPPORTED_CONNECTOR_PROFILE_TYPE = "UNSUPPORTED_CONNECTOR_PROFILE_TYPE"


class ConnectorResourceError(Exception):
"""
Expand Down
28 changes: 26 additions & 2 deletions samtranslator/model/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from abc import ABC, abstractmethod
from collections import defaultdict
from enum import Enum
from typing import List, Optional, Sequence, Union
from typing import Any, Dict, List, Optional, Sequence, Union


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

@property
def metadata(self) -> Optional[Dict[str, Any]]:
"""Return the exception metadata."""


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

Expand All @@ -37,6 +43,17 @@ def message(self) -> str:
len(self.causes)
)

@property
def metadata(self) -> Dict[str, List[Any]]:
# Merge metadata in each exception to one single metadata dictionary
metadata_dict = defaultdict(list)
for cause in self.causes:
if not cause.metadata:
continue
for k, v in cause.metadata.items():
metadata_dict[k].append(v)
return metadata_dict

@property
def causes(self) -> Sequence[ExceptionWithMessage]:
return self._causes
Expand Down Expand Up @@ -86,9 +103,12 @@ class InvalidResourceException(ExceptionWithMessage):
message -- explanation of the error
"""

def __init__(self, logical_id: Union[str, List[str]], message: str) -> None:
def __init__(
self, logical_id: Union[str, List[str]], message: str, metadata: Optional[Dict[str, Any]] = None
) -> None:
self._logical_id = logical_id
self._message = message
self._metadata = metadata

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

@property
def metadata(self) -> Optional[Dict[str, Any]]:
return self._metadata


class InvalidResourcePropertyTypeException(InvalidResourceException):
def __init__(
Expand Down
2 changes: 2 additions & 0 deletions samtranslator/model/sam_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from samtranslator.model.architecture import ARM64, X86_64
from samtranslator.model.cloudformation import NestedStack
from samtranslator.model.connector.connector import (
UNSUPPORTED_CONNECTOR_PROFILE_TYPE,
ConnectorResourceError,
ConnectorResourceReference,
add_depends_on,
Expand Down Expand Up @@ -1861,6 +1862,7 @@ def generate_resources(
raise InvalidResourceException(
self.logical_id,
f"Unable to create connector from {source.resource_type} to {destination.resource_type}; it's not supported or the template is invalid.",
{UNSUPPORTED_CONNECTOR_PROFILE_TYPE: {source.resource_type: destination.resource_type}},
)

# removing duplicate permissions
Expand Down
64 changes: 64 additions & 0 deletions tests/model/test_exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from unittest import TestCase

from samtranslator.model.exceptions import (
DuplicateLogicalIdException,
InvalidResourceException,
InvalidDocumentException,
InvalidTemplateException,
InvalidEventException,
)


class TestExceptions(TestCase):
def setUp(self) -> None:
self.invalid_template = InvalidTemplateException("foo")
self.duplicate_id = DuplicateLogicalIdException("foo", "bar", "type")
self.invalid_resource = InvalidResourceException("foo", "bar")
self.invalid_event = InvalidEventException("foo", "bar")
self.invalid_resource_with_metadata = InvalidResourceException("foo-bar", "foo", {"hello": "world"})

def test_invalid_template(self):
self.assertEqual(self.invalid_template.metadata, None)
self.assertIn("Structure of the SAM template is invalid", self.invalid_template.message)

def test_duplicate_id(self):
self.assertEqual(self.duplicate_id.metadata, None)
self.assertIn("Transforming resource with id", self.duplicate_id.message)

def test_invalid_resource_without_metadata(self):
self.assertEqual(self.invalid_resource.metadata, None)
self.assertIn("Resource with id [foo] is invalid", self.invalid_resource.message)

def test_invalid_resource_with_metadata(self):
self.assertEqual(self.invalid_resource_with_metadata.metadata, {"hello": "world"})
self.assertIn("Resource with id [foo-bar] is invalid", self.invalid_resource_with_metadata.message)

def test_invalid_event(self):
self.assertEqual(self.invalid_event.metadata, None)
self.assertIn("Event with id [foo] is invalid.", self.invalid_event.message)

def test_invalid_document_exceptions(self):
unsupported_connector_profile = InvalidResourceException("hello", "world", {"KEY": {"C": "D"}})
unsupported_connector_profile2 = InvalidResourceException("foobar", "bar", {"KEY": {"A": "B"}})
self.assertEqual(unsupported_connector_profile.metadata, {"KEY": {"C": "D"}})
self.assertEqual(unsupported_connector_profile2.metadata, {"KEY": {"A": "B"}})

invalid_document_exception = InvalidDocumentException(
[
self.invalid_template,
self.duplicate_id,
self.invalid_resource,
self.invalid_event,
self.invalid_resource_with_metadata,
unsupported_connector_profile,
unsupported_connector_profile2,
]
)
self.assertEqual(
"Invalid Serverless Application Specification document. Number of errors found: 7.",
invalid_document_exception.message,
)
self.assertEqual(
invalid_document_exception.metadata,
{"hello": ["world"], "KEY": [{"C": "D"}, {"A": "B"}]},
)

0 comments on commit 230f745

Please sign in to comment.