Skip to content

Commit 1662e0b

Browse files
committed
Address Feedback
1 parent 5587db0 commit 1662e0b

File tree

5 files changed

+126
-184
lines changed

5 files changed

+126
-184
lines changed

samtranslator/internal/resource_validator.py

-18
This file was deleted.

samtranslator/model/__init__.py

+26-1
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,20 @@
22
import inspect
33
import re
44
from abc import ABC, ABCMeta, abstractmethod
5-
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
5+
from contextlib import suppress
6+
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, TypeVar, Union
7+
8+
from pydantic import BaseModel
9+
from pydantic.error_wrappers import ValidationError
610

711
from samtranslator.intrinsics.resolver import IntrinsicsResolver
812
from samtranslator.model.exceptions import ExpectedType, InvalidResourceException, InvalidResourcePropertyTypeException
913
from samtranslator.model.tags.resource_tagging import get_tag_list
1014
from samtranslator.model.types import IS_DICT, IS_STR, Validator, any_type, is_type
1115
from samtranslator.plugins import LifeCycleEvents
1216

17+
RT = TypeVar("RT", bound=BaseModel) # return type
18+
1319

1420
class PropertyType:
1521
"""Stores validation information for a CloudFormation resource property.
@@ -312,6 +318,25 @@ def __setattr__(self, name, value): # type: ignore[no-untyped-def]
312318
),
313319
)
314320

321+
# Note: For compabitliy issue, we should ONLY use this with new abstraction/resources.
322+
def validate_properties_and_return_model(self, cls: Type[RT]) -> RT:
323+
"""
324+
Given a resource properties, return a typed object from the definitions of SAM schema model
325+
326+
param:
327+
resource_properties: properties from input template
328+
cls: schema models
329+
"""
330+
try:
331+
return cls.parse_obj(self._generate_resource_dict()["Properties"])
332+
except ValidationError as e:
333+
error_properties: str = ""
334+
with suppress(KeyError):
335+
error_properties = ", ".join([str(error["loc"][0]) for error in e.errors()])
336+
raise InvalidResourceException(
337+
self.logical_id, f"Given resource property '{error_properties}' is invalid"
338+
) from e
339+
315340
def validate_properties(self) -> None:
316341
"""Validates that the required properties for this Resource have been populated, and that all properties have
317342
valid values.
+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
from unittest import TestCase
2+
3+
from samtranslator.internal.schema_source.aws_serverless_connector import Properties as ConnectorProperties
4+
from samtranslator.internal.schema_source.aws_serverless_function import Properties as FunctionProperties
5+
from samtranslator.model.exceptions import InvalidResourceException
6+
from samtranslator.model.sam_resources import (
7+
SamConnector,
8+
SamFunction,
9+
)
10+
11+
12+
class TestResourceValidator(TestCase):
13+
def setUp(self) -> None:
14+
self.connector = SamConnector("foo")
15+
self.connector.Source = {
16+
"Arn": "random-arn",
17+
"Type": "random-type",
18+
}
19+
self.connector.Destination = {"Id": "MyTable"}
20+
self.connector.Permissions = ["Read"]
21+
22+
self.function = SamFunction("function")
23+
self.function.CodeUri = "s3://foobar/foo.zip"
24+
self.function.Runtime = "foo"
25+
self.function.Handler = "bar"
26+
self.function.FunctionUrlConfig = {"Cors": {"AllowOrigins": ["example1.com"]}, "AuthType": "123"}
27+
self.function.Events = {
28+
"MyMqEvent": {
29+
"Type": "MQ",
30+
"Properties": {
31+
"Broker": {"Fn::GetAtt": "MyMqBroker.Arn"},
32+
"Queues": ["TestQueue"],
33+
"SourceAccessConfigurations": [{"Type": "BASIC_AUTH"}],
34+
},
35+
}
36+
}
37+
38+
def test_connector_model(self):
39+
connector_model = self.connector.validate_properties_and_return_model(
40+
ConnectorProperties,
41+
)
42+
self.assertEqual(connector_model.Source.Arn, "random-arn")
43+
self.assertEqual(connector_model.Source.Type, "random-type")
44+
self.assertEqual(connector_model.Source.Id, None)
45+
self.assertEqual(connector_model.Destination.Id, "MyTable")
46+
self.assertEqual(connector_model.Permissions, ["Read"])
47+
48+
def test_lambda_model(self):
49+
model = self.function.validate_properties_and_return_model(FunctionProperties)
50+
self.assertEqual(model.CodeUri, "s3://foobar/foo.zip")
51+
self.assertEqual(model.Runtime, "foo")
52+
self.assertEqual(model.Handler, "bar")
53+
self.assertEqual(model.FunctionUrlConfig.Cors, {"AllowOrigins": ["example1.com"]})
54+
self.assertEqual(model.FunctionUrlConfig.AuthType, "123")
55+
self.assertEqual(model.Events["MyMqEvent"].Type, "MQ")
56+
self.assertEqual(model.Events["MyMqEvent"].Properties.Broker, {"Fn::GetAtt": "MyMqBroker.Arn"})
57+
self.assertEqual(model.Events["MyMqEvent"].Properties.Queues, ["TestQueue"])
58+
self.assertEqual(model.Events["MyMqEvent"].Properties.SourceAccessConfigurations, [{"Type": "BASIC_AUTH"}])
59+
60+
61+
class TestResourceValidatorFailure(TestCase):
62+
def test_connector_with_empty_properties(self):
63+
invalid_connector = SamConnector("foo")
64+
with self.assertRaises(
65+
InvalidResourceException,
66+
):
67+
invalid_connector.validate_properties_and_return_model(ConnectorProperties)
68+
self.assertRegex(".+Given resource property '(Source|Destination|Permissions)'.+ is invalid.")
69+
70+
def test_connector_without_source(self):
71+
invalid_connector = SamConnector("foo")
72+
invalid_connector.Destination = {"Id": "MyTable"}
73+
invalid_connector.Permissions = ["Read"]
74+
with self.assertRaises(
75+
InvalidResourceException,
76+
):
77+
invalid_connector.validate_properties_and_return_model(ConnectorProperties)
78+
self.assertRegex(".+Given resource property 'Source'.+ is invalid.")
79+
80+
def test_connector_with_invalid_permission(self):
81+
invalid_connector = SamConnector("foo")
82+
invalid_connector.Source = {"Id": "MyTable"}
83+
invalid_connector.Destination = {"Id": "MyTable"}
84+
invalid_connector.Permissions = ["Invoke"]
85+
with self.assertRaises(
86+
InvalidResourceException,
87+
):
88+
invalid_connector.validate_properties_and_return_model(ConnectorProperties)
89+
self.assertRegex(".+Given resource property 'Permissions'.+ is invalid.")
90+
91+
def test_connector_with_invalid_permission_type(self):
92+
invalid_connector = SamConnector("foo")
93+
invalid_connector.Source = {"Id": "MyTable"}
94+
invalid_connector.Destination = {"Id": "MyTable"}
95+
invalid_connector.Permissions = {"Hello": "World"}
96+
with self.assertRaises(
97+
InvalidResourceException,
98+
):
99+
invalid_connector.validate_properties_and_return_model(ConnectorProperties)
100+
self.assertRegex(".+Given resource property 'Permissions'.+ is invalid.")

tests/validator/input/connector/error_connector.yaml

-55
This file was deleted.

tests/validator/test_resource_validator.py

-110
This file was deleted.

0 commit comments

Comments
 (0)