Skip to content

Commit 463b927

Browse files
committed
Add more tests
1 parent 78b7d09 commit 463b927

File tree

2 files changed

+93
-20
lines changed

2 files changed

+93
-20
lines changed

samtranslator/validator/resource_validator.py

+20-13
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,44 @@
44
from pydantic import BaseModel
55

66

7-
class ResourceModel:
7+
class Model:
88
"""
99
Wrapper class around a SAM schema BaseModel to with a new functional "get" method
1010
"""
1111

1212
def __init__(self, model: BaseModel) -> None:
1313
self.model = model
1414

15-
def get(self, attr: str, default_value: Any = None) -> Any:
16-
attr_value = self.model.__dict__.get(attr, default_value)
15+
def _process_attr_value(self, attr_value: Any) -> Any:
1716
if isinstance(attr_value, BaseModel):
1817
if "__root__" in attr_value.__dict__:
1918
return attr_value.__dict__["__root__"]
20-
return ResourceModel(attr_value)
19+
return Model(attr_value)
2120
return attr_value
2221

23-
def __getitem__(self, attr: str) -> Any:
24-
attr_value = self.model.__dict__[attr]
25-
if isinstance(attr_value, BaseModel):
26-
if "__root__" in attr_value.__dict__:
27-
return attr_value.__dict__["__root__"]
28-
return ResourceModel(attr_value)
29-
return attr_value
22+
def _get_item(self, attr_value: Any) -> Any:
23+
if isinstance(attr_value, list):
24+
return [self._process_attr_value(attr) for attr in attr_value]
25+
return self._process_attr_value(attr_value)
26+
27+
def get(self, attr_key: str, default_value: Any = None) -> Any:
28+
"""Return the value for key if key is in Model properties else default."""
29+
attr_value = self.model.__dict__.get(attr_key, default_value)
30+
return self._get_item(attr_value)
31+
32+
def __getitem__(self, attr_key: str) -> Any:
33+
"""Return the value for key if key is in Model properties else raise KeyError exception."""
34+
attr_value = self.model.__dict__[attr_key]
35+
return self._get_item(attr_value)
3036

3137

32-
def to_resource_model(resource_properties: Dict[Any, Any], cls: Type[BaseModel]) -> ResourceModel:
38+
# Note: For compabitliy issue, we should ONLY use this with new abstraction/resources.
39+
def to_model(resource_properties: Dict[Any, Any], cls: Type[BaseModel]) -> Model:
3340
"""
3441
Given properties of a SAM resource return a typed object from the definitions of SAM schema model
3542
3643
param:
3744
resource_properties: properties from input template
3845
cls: SAM schema models
3946
"""
40-
return ResourceModel(cls(**resource_properties))
47+
return Model(cls(**resource_properties))

tests/validator/test_resource_validator.py

+73-7
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,46 @@
11
import os.path
2+
from typing import Dict, List
23
from unittest import TestCase
34

5+
from pydantic import BaseModel
46
from pydantic.error_wrappers import ValidationError
5-
from samtranslator.validator.resource_validator import to_resource_model
7+
from samtranslator.validator.resource_validator import to_model
68
from samtranslator.yaml_helper import yaml_parse
79
from schema_source.aws_serverless_connector import Properties as ConnectorProperties
810

911
BASE_PATH = os.path.dirname(__file__)
1012
CONNECTOR_INPUT_FOLDER = os.path.join(BASE_PATH, "input", "connector")
1113

1214

13-
class TestResourceModel(TestCase):
15+
class Random(BaseModel):
16+
value: int
17+
18+
19+
class Tag(BaseModel):
20+
A: str
21+
B: int
22+
23+
24+
class Content(BaseModel):
25+
Tags: Tag
26+
27+
28+
class Contents(BaseModel):
29+
Content: Content
30+
31+
32+
class Properties(BaseModel):
33+
Key: Dict[str, Random]
34+
Hello: List[str]
35+
Random: Random
36+
37+
38+
class ValidatiorBaseModel(BaseModel):
39+
Properties: Properties
40+
Contents: List[Contents]
41+
42+
43+
class TestModel(TestCase):
1444
def setUp(self) -> None:
1545
self.connector_template = {
1646
"Source": {
@@ -21,8 +51,17 @@ def setUp(self) -> None:
2151
"Permissions": ["Read"],
2252
}
2353

24-
def test_resource_model_get(self):
25-
connector_model = to_resource_model(
54+
self.model_template = {
55+
"Properties": {"Key": {"A": {"value": 10}}, "Hello": ["1", "2", "3"], "Random": {"value": 5}},
56+
"Contents": [
57+
{"Content": {"Tags": {"A": "hello", "B": 5}}},
58+
{"Content": {"Tags": {"A": "wow", "B": 10}}},
59+
{"Content": {"Tags": {"A": "no", "B": -5}}},
60+
],
61+
}
62+
63+
def test_connector_model_get_operation(self):
64+
connector_model = to_model(
2665
self.connector_template,
2766
ConnectorProperties,
2867
)
@@ -38,9 +77,24 @@ def test_resource_model_get(self):
3877
self.assertEqual(connector_model["Destination"]["Id"], "MyTable")
3978
self.assertEqual(connector_model["Permissions"], ["Read"])
4079

80+
def test_model_get_operation(self):
81+
model = to_model(self.model_template, ValidatiorBaseModel)
82+
self.assertEqual(model["Properties"]["Key"], {"A": {"value": 10}})
83+
self.assertEqual(model["Properties"]["Key"]["A"], {"value": 10})
84+
self.assertEqual(model["Properties"]["Hello"], ["1", "2", "3"])
85+
self.assertEqual(model.get("Properties").get("Random")["value"], 5)
86+
self.assertEqual(model.get("DoNotExist"), None)
87+
88+
self.assertEqual(len(model["Contents"]), 3)
89+
self.assertEqual(model["Contents"][0]["Content"]["Tags"]["A"], "hello")
90+
self.assertEqual(model["Contents"][0]["Content"]["Tags"]["B"], 5)
91+
self.assertEqual(model["Contents"][1]["Content"]["Tags"]["A"], "wow")
92+
self.assertEqual(model["Contents"][0]["Content"]["Tags"].get("C"), None)
93+
self.assertEqual(model["Contents"][2]["Content"]["Tags"]["B"], -5)
4194

42-
class TestResourceValidatorFailure(TestCase):
43-
def test_to_resource_model_error_connector_template(self):
95+
96+
class TestModelValidatorFailure(TestCase):
97+
def test_to_model_error_connector_template(self):
4498
manifest = yaml_parse(open(os.path.join(CONNECTOR_INPUT_FOLDER, "error_connector.yaml")))
4599
for _, resource in manifest["Resources"].items():
46100
properties = resource["Properties"]
@@ -49,4 +103,16 @@ def test_to_resource_model_error_connector_template(self):
49103
ValidationError,
50104
"[1-9] validation error for Properties(.|\n)+(Source|Destination|Permissions)(.|\n)*(field required)|(unexpected value)|(str type expected)|(value is not a valid list).+",
51105
):
52-
to_resource_model(properties, ConnectorProperties)
106+
to_model(properties, ConnectorProperties)
107+
108+
def test_to_model_test_base_model(self):
109+
invalid_model_template = {
110+
"Properties": {"Key": "123", "Hello": 5, "Random": {}},
111+
"Contents": [{"Content": {"Tags": {"A": "hello", "B": 5}}}, {"Content": {"Tags": {"A": "wow"}}}],
112+
}
113+
114+
with self.assertRaisesRegex(
115+
ValidationError,
116+
"[1-9] validation error for TestBaseModel(.|\n)+(Contents)(.|\n)*(field required)|(unexpected value)|(str type expected)|(value is not a valid list).+",
117+
):
118+
to_model(invalid_model_template, ValidatiorBaseModel)

0 commit comments

Comments
 (0)