From c9ef5290f8e4663492d4dfaa40f59c14bcb72ebd Mon Sep 17 00:00:00 2001 From: Lucas <12496191+lucashuy@users.noreply.github.com> Date: Fri, 23 Sep 2022 10:05:20 -0700 Subject: [PATCH 1/5] Added module output resolving --- .../hooks/prepare/resource_linking.py | 53 ++++++++++++++++++- .../hooks/prepare/test_resource_linking.py | 43 ++++++++++++++- 2 files changed, 92 insertions(+), 4 deletions(-) diff --git a/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py b/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py index 545662b034..4f2d46324c 100644 --- a/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py +++ b/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py @@ -99,13 +99,62 @@ def _get_configuration_address(address: str) -> str: Cleans all addresses of indices and returns a clean address Parameters - ========== + ---------- address : str The address to clean Returns - ======= + ------- str The address clean of indices """ return re.sub(r"\[[^\[\]]*\]", "", address) + + +def _resolve_module_output(module: TFModule, output_name: str) -> List[Union[ConstantValue, ResolvedReference]]: + """ + Resolves any references in the output section of the module + + Parameters + ---------- + module : Module + The module with outputs to search + output_name : str + The value to resolve + + Returns + ------- + List[Union[ConstantValue, ResolvedReference]] + A list of resolved values + """ + results: List[Union[ConstantValue, ResolvedReference]] = [] + + output = module.outputs[output_name] + output_value = output.value + + if isinstance(output, ConstantValue): + results.append(output) + elif isinstance(output, References): + cleaned_references = _clean_references_list(output_value) + + for reference in cleaned_references: + if reference.startswith("var."): + stripped_reference = _get_configuration_address(reference[4:]) + results += _resolve_module_variable(module, stripped_reference) + elif reference.startswith("module."): + # aaa.bbb.ccc => bbb + module_name = reference[7 : reference.rfind(".")] + # aaa.bbb.ccc => ccc + output_name = reference[reference.rfind(".") + 1 :] + + stripped_reference = _get_configuration_address(module_name) + + results += _resolve_module_output(module.child_modules[stripped_reference], output_name) + else: + results.append(ResolvedReference(reference, module.full_address or "")) + + return results + + +def _resolve_module_variable(module: TFModule, variable: str): + pass diff --git a/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py b/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py index 785b409c29..b9b7317e47 100644 --- a/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py +++ b/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py @@ -1,16 +1,17 @@ from copy import deepcopy from unittest import TestCase -from unittest.mock import Mock +from unittest.mock import Mock, patch from parameterized import parameterized from samcli.hook_packages.terraform.hooks.prepare.resource_linking import ( _clean_references_list, _get_configuration_address, + _resolve_module_output, TFModule, TFResource, - ConstantValue, References, + ConstantValue, ) @@ -131,3 +132,41 @@ def test_resource_full_address_root_module(self): module = TFModule(None, None, {}, {}, {}, {}) resource = TFResource("resource_address", "type", module, {}) self.assertEqual(resource.full_address, "resource_address") + + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._resolve_module_variable") + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") + def test_resolve_module_output_with_var(self, config_mock, resolve_var_mock): + module = TFModule("", None, {"mycoolref": "mycoolvar"}, [], {}, {"mycooloutput": References(["var.mycoolref"])}) + + config_mock.return_value = "mycoolref" + + _resolve_module_output(module, "mycooloutput") + + config_mock.assert_called_with("mycoolref") + resolve_var_mock.assert_called_with(module, "mycoolref") + + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") + def test_resolve_module_output_with_module(self, config_mock): + module = TFModule("", None, {}, [], {}, {"mycooloutput": References(["module.mycoolmod"])}) + module2 = TFModule("module.mycoolmod", module, {}, [], {}, {"mycoolmod": ConstantValue("mycoolconst")}) + module.child_modules.update({"mycoolmod": module2}) + + config_mock.return_value = "mycoolmod" + + results = _resolve_module_output(module, "mycooloutput") + + self.assertEqual(len(results), 1) + self.assertEqual(results[0].value, "mycoolconst") + + @parameterized.expand( + [ + (TFModule("", None, {}, [], {}, {"mycooloutput": ConstantValue("mycoolconst")}),), + (TFModule("", None, {}, [], {}, {"mycooloutput": References(["mycoolconst"])}),), + ] + ) + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") + def test_resolve_module_output_already_resolved(self, module, config_mock): + results = _resolve_module_output(module, "mycooloutput") + + self.assertEqual(len(results), 1) + self.assertEqual(results[0].value, "mycoolconst") From 1117b3631bad530a7934d442fdfb7e3666b06268 Mon Sep 17 00:00:00 2001 From: Lucas <12496191+lucashuy@users.noreply.github.com> Date: Wed, 28 Sep 2022 09:54:37 -0700 Subject: [PATCH 2/5] Address comments --- .../terraform/hooks/prepare/exceptions.py | 11 +++ .../hooks/prepare/resource_linking.py | 62 +++++++++++- .../hooks/prepare/test_resource_linking.py | 96 +++++++++++++++++-- 3 files changed, 156 insertions(+), 13 deletions(-) create mode 100644 samcli/hook_packages/terraform/hooks/prepare/exceptions.py diff --git a/samcli/hook_packages/terraform/hooks/prepare/exceptions.py b/samcli/hook_packages/terraform/hooks/prepare/exceptions.py new file mode 100644 index 0000000000..4e32131e98 --- /dev/null +++ b/samcli/hook_packages/terraform/hooks/prepare/exceptions.py @@ -0,0 +1,11 @@ +""" +Module containing prepare hook-related exceptions +""" + + +class InvalidResourceLinkingException(Exception): + fmt = "An error occurred when attempting to link two resources: {message}" + + def __init__(self, message): + msg = self.fmt.format(message=message) + Exception.__init__(self, msg) diff --git a/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py b/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py index 4f2d46324c..ded6be3acc 100644 --- a/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py +++ b/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py @@ -3,9 +3,14 @@ e.g. linking layers to functions """ +import logging + from dataclasses import dataclass from typing import Any, Dict, List, Optional, Union import re +from samcli.hook_packages.terraform.hooks.prepare.exceptions import InvalidResourceLinkingException + +LOG = logging.getLogger(__name__) @dataclass @@ -129,28 +134,77 @@ def _resolve_module_output(module: TFModule, output_name: str) -> List[Union[Con """ results: List[Union[ConstantValue, ResolvedReference]] = [] - output = module.outputs[output_name] + output = module.outputs.get(output_name) + + if not output: + raise InvalidResourceLinkingException(f"Output {output_name} was not found in module {module.full_address}") + output_value = output.value + LOG.debug("Resolving output {%s} for module {%s}", output_name, module.full_address) + if isinstance(output, ConstantValue): + LOG.debug( + "Resolved constant value {%s} for module {%s} for output {%s}", + output.value, + module.full_address, + output_name, + ) + results.append(output) elif isinstance(output, References): + LOG.debug("Found references for module {%s} for output {%s}", module.full_address, output_name) + cleaned_references = _clean_references_list(output_value) for reference in cleaned_references: if reference.startswith("var."): + LOG.debug( + "Resolving variable reference {%s} for module {%s} for output {%s}", + reference, + module.full_address, + output_name, + ) + stripped_reference = _get_configuration_address(reference[4:]) results += _resolve_module_variable(module, stripped_reference) elif reference.startswith("module."): - # aaa.bbb.ccc => bbb + LOG.debug( + "Resolving module reference {%s} for module {%s} for output {%s}", + reference, + module.full_address, + output_name, + ) + + # module.bbb.ccc => bbb module_name = reference[7 : reference.rfind(".")] - # aaa.bbb.ccc => ccc + # module.bbb.ccc => ccc output_name = reference[reference.rfind(".") + 1 :] stripped_reference = _get_configuration_address(module_name) - results += _resolve_module_output(module.child_modules[stripped_reference], output_name) + if not module.child_modules: + raise InvalidResourceLinkingException( + f"Module {module.full_address} does not have child modules defined, possible misconfiguration" + ) + + child_module = module.child_modules.get(stripped_reference) + + if not child_module: + raise InvalidResourceLinkingException( + f"Module {module.full_address} does not have {stripped_reference} as a child module" + ", possible misconfiguration" + ) + + results += _resolve_module_output(child_module, output_name) else: + LOG.debug( + "Resolved reference {%s} for module {%s} for output {%s}", + reference, + module.full_address, + output_name, + ) + results.append(ResolvedReference(reference, module.full_address or "")) return results diff --git a/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py b/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py index b9b7317e47..83f8cfd9cc 100644 --- a/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py +++ b/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py @@ -3,8 +3,10 @@ from unittest.mock import Mock, patch from parameterized import parameterized +from samcli.hook_packages.terraform.hooks.prepare.exceptions import InvalidResourceLinkingException from samcli.hook_packages.terraform.hooks.prepare.resource_linking import ( + ResolvedReference, _clean_references_list, _get_configuration_address, _resolve_module_output, @@ -135,10 +137,19 @@ def test_resource_full_address_root_module(self): @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._resolve_module_variable") @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") - def test_resolve_module_output_with_var(self, config_mock, resolve_var_mock): - module = TFModule("", None, {"mycoolref": "mycoolvar"}, [], {}, {"mycooloutput": References(["var.mycoolref"])}) + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._clean_references_list") + def test_resolve_module_output_with_var(self, clean_ref_mock, config_mock, resolve_var_mock): + module = TFModule( + None, + None, + {"mycoolref": ConstantValue("mycoolvar")}, + [], + {}, + {"mycooloutput": References(["var.mycoolref"])}, + ) config_mock.return_value = "mycoolref" + clean_ref_mock.return_value = ["var.mycoolref"] _resolve_module_output(module, "mycooloutput") @@ -146,27 +157,94 @@ def test_resolve_module_output_with_var(self, config_mock, resolve_var_mock): resolve_var_mock.assert_called_with(module, "mycoolref") @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") - def test_resolve_module_output_with_module(self, config_mock): - module = TFModule("", None, {}, [], {}, {"mycooloutput": References(["module.mycoolmod"])}) - module2 = TFModule("module.mycoolmod", module, {}, [], {}, {"mycoolmod": ConstantValue("mycoolconst")}) + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._clean_references_list") + def test_resolve_module_output_with_module(self, clean_ref_mock, config_mock): + module = TFModule(None, None, {}, [], {}, {"mycooloutput": References(["module.mycoolmod.mycooloutput2"])}) + module2 = TFModule("module.mycoolmod", module, {}, [], {}, {"mycooloutput2": ConstantValue("mycoolconst")}) module.child_modules.update({"mycoolmod": module2}) config_mock.return_value = "mycoolmod" + clean_ref_mock.return_value = ["module.mycoolmod.mycooloutput2"] + + results = _resolve_module_output(module, "mycooloutput") + + self.assertEqual(len(results), 1) + self.assertEqual(results[0].value, "mycoolconst") + + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._clean_references_list") + def test_resolve_module_output_already_resolved_constant(self, clean_ref_mock, config_mock): + module = TFModule(None, None, {}, [], {}, {"mycooloutput": ConstantValue("mycoolconst")}) results = _resolve_module_output(module, "mycooloutput") self.assertEqual(len(results), 1) self.assertEqual(results[0].value, "mycoolconst") + self.assertIsInstance(results[0], ConstantValue) @parameterized.expand( [ - (TFModule("", None, {}, [], {}, {"mycooloutput": ConstantValue("mycoolconst")}),), - (TFModule("", None, {}, [], {}, {"mycooloutput": References(["mycoolconst"])}),), + ( + TFModule("module.name", None, {}, [], {}, {"mycooloutput": References(["local.mycoolconst"])}), + "module.name", + ), + (TFModule(None, None, {}, [], {}, {"mycooloutput": References(["local.mycoolconst"])}), ""), ] ) @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") - def test_resolve_module_output_already_resolved(self, module, config_mock): + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._clean_references_list") + def test_resolve_module_output_already_resolved_reference(self, module, expected_addr, clean_ref_mock, config_mock): + clean_ref_mock.return_value = ["local.mycoolconst"] + results = _resolve_module_output(module, "mycooloutput") self.assertEqual(len(results), 1) - self.assertEqual(results[0].value, "mycoolconst") + self.assertEqual(results[0].value, "local.mycoolconst") + self.assertEqual(results[0].module_address, expected_addr) + self.assertIsInstance(results[0], ResolvedReference) + + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._clean_references_list") + def test_resolve_module_output_raises_exception_empty_output(self, clean_ref_mock, get_config_mock): + module = TFModule("module.mymod", None, {}, [], {}, {}) + + with self.assertRaises(InvalidResourceLinkingException) as err: + _resolve_module_output(module, "empty") + + self.assertEqual( + str(err.exception), + "An error occurred when attempting to link two resources: Output empty was not found in module module.mymod", + ) + + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._clean_references_list") + def test_resolve_module_output_raises_exception_empty_children(self, clean_ref_mock, get_config_mock): + module = TFModule("module.mymod", None, {}, [], {}, {"search": References(["module.nonexist.output"])}) + + clean_ref_mock.return_value = ["module.nonexist"] + get_config_mock.return_value = "nonexist" + + with self.assertRaises(InvalidResourceLinkingException) as err: + _resolve_module_output(module, "search") + + self.assertEqual( + str(err.exception), + "An error occurred when attempting to link two resources: Module module.mymod does not have child modules defined, possible misconfiguration", + ) + + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._clean_references_list") + def test_resolve_module_output_raises_exception_non_exist_child(self, clean_ref_mock, get_config_mock): + module = TFModule( + "module.mymod", None, {}, [], {"othermod": Mock()}, {"search": References(["module.nonexist.output"])} + ) + clean_ref_mock.return_value = ["module.nonexist.output"] + get_config_mock.return_value = "nonexist" + + with self.assertRaises(InvalidResourceLinkingException) as err: + _resolve_module_output(module, "search") + + self.assertEqual( + str(err.exception), + "An error occurred when attempting to link two resources: Module module.mymod does not have nonexist as a child module, possible misconfiguration", + ) From c9e04ff9f60a93a3c21415b40703a38baf446ee4 Mon Sep 17 00:00:00 2001 From: Lucas <12496191+lucashuy@users.noreply.github.com> Date: Wed, 28 Sep 2022 11:45:41 -0700 Subject: [PATCH 3/5] Change magic constant to use find() instead --- .../hook_packages/terraform/hooks/prepare/resource_linking.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py b/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py index ded6be3acc..e6cbad378b 100644 --- a/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py +++ b/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py @@ -166,7 +166,7 @@ def _resolve_module_output(module: TFModule, output_name: str) -> List[Union[Con output_name, ) - stripped_reference = _get_configuration_address(reference[4:]) + stripped_reference = _get_configuration_address(reference[reference.find(".") + 1 :]) results += _resolve_module_variable(module, stripped_reference) elif reference.startswith("module."): LOG.debug( @@ -177,7 +177,7 @@ def _resolve_module_output(module: TFModule, output_name: str) -> List[Union[Con ) # module.bbb.ccc => bbb - module_name = reference[7 : reference.rfind(".")] + module_name = reference[reference.find(".") + 1 : reference.rfind(".")] # module.bbb.ccc => ccc output_name = reference[reference.rfind(".") + 1 :] From 224d63090d793228a52fbd153b1cbe329341e862 Mon Sep 17 00:00:00 2001 From: Lucas <12496191+lucashuy@users.noreply.github.com> Date: Thu, 29 Sep 2022 13:18:32 -0700 Subject: [PATCH 4/5] Addressed comments --- .../hooks/prepare/resource_linking.py | 17 ++++--- .../hooks/prepare/test_resource_linking.py | 45 ++++++++++++++++--- 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py b/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py index f02fc26dc0..953863ec68 100644 --- a/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py +++ b/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py @@ -28,7 +28,7 @@ class References: @dataclass class ResolvedReference: value: str - module_address: str + module_address: Optional[str] @dataclass @@ -179,6 +179,12 @@ def _resolve_module_output(module: TFModule, output_name: str) -> List[Union[Con output_name, ) + # validate that the reference is in the format: module.name.output + if re.fullmatch(r"module(?:\.[^\.]+){2}", reference) is None: + raise InvalidResourceLinkingException( + f"Module {module.full_address} contains an invalid reference {reference}" + ) + # module.bbb.ccc => bbb module_name = reference[reference.find(".") + 1 : reference.rfind(".")] # module.bbb.ccc => ccc @@ -188,7 +194,7 @@ def _resolve_module_output(module: TFModule, output_name: str) -> List[Union[Con if not module.child_modules: raise InvalidResourceLinkingException( - f"Module {module.full_address} does not have child modules defined, possible misconfiguration" + f"Module {module.full_address} does not have child modules defined" ) child_module = module.child_modules.get(stripped_reference) @@ -196,7 +202,6 @@ def _resolve_module_output(module: TFModule, output_name: str) -> List[Union[Con if not child_module: raise InvalidResourceLinkingException( f"Module {module.full_address} does not have {stripped_reference} as a child module" - ", possible misconfiguration" ) results += _resolve_module_output(child_module, output_name) @@ -208,7 +213,7 @@ def _resolve_module_output(module: TFModule, output_name: str) -> List[Union[Con output_name, ) - results.append(ResolvedReference(reference, module.full_address or "")) + results.append(ResolvedReference(reference, module.full_address)) return results @@ -253,7 +258,9 @@ def _resolve_module_variable(module: TFModule, variable_name: str) -> List[Union and module.parent_module.child_modules and module.parent_module.child_modules.get(config_module_name) ): - child_module = module.parent_module.child_modules.get(config_module_name) + # using .get() gives us Optional[TFModule], if conditional already validates child module exists + # access list directly instead + child_module = module.parent_module.child_modules[config_module_name] results += _resolve_module_output(child_module, output_name) else: raise InvalidResourceLinkingException(f"Couldn't find child module {config_module_name}.") diff --git a/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py b/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py index 8122ec4480..78b76796c5 100644 --- a/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py +++ b/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py @@ -141,10 +141,12 @@ def test_resource_full_address_root_module(self): @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._clean_references_list") def test_resolve_module_output_with_var(self, clean_ref_mock, config_mock, resolve_var_mock): + constant_val = ConstantValue("mycoolvar") + module = TFModule( None, None, - {"mycoolref": ConstantValue("mycoolvar")}, + {"mycoolref": constant_val}, [], {}, {"mycooloutput": References(["var.mycoolref"])}, @@ -152,12 +154,18 @@ def test_resolve_module_output_with_var(self, clean_ref_mock, config_mock, resol config_mock.return_value = "mycoolref" clean_ref_mock.return_value = ["var.mycoolref"] + resolve_var_mock.return_value = [constant_val] - _resolve_module_output(module, "mycooloutput") + results = _resolve_module_output(module, "mycooloutput") + # assert we are calling the right funcs config_mock.assert_called_with("mycoolref") resolve_var_mock.assert_called_with(module, "mycoolref") + # assert we still return valid results + self.assertEqual(len(results), 1) + self.assertEqual(results[0].value, "mycoolvar") + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._clean_references_list") def test_resolve_module_output_with_module(self, clean_ref_mock, config_mock): @@ -190,7 +198,7 @@ def test_resolve_module_output_already_resolved_constant(self, clean_ref_mock, c TFModule("module.name", None, {}, [], {}, {"mycooloutput": References(["local.mycoolconst"])}), "module.name", ), - (TFModule(None, None, {}, [], {}, {"mycooloutput": References(["local.mycoolconst"])}), ""), + (TFModule(None, None, {}, [], {}, {"mycooloutput": References(["local.mycoolconst"])}), None), ] ) @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") @@ -223,7 +231,7 @@ def test_resolve_module_output_raises_exception_empty_output(self, clean_ref_moc def test_resolve_module_output_raises_exception_empty_children(self, clean_ref_mock, get_config_mock): module = TFModule("module.mymod", None, {}, [], {}, {"search": References(["module.nonexist.output"])}) - clean_ref_mock.return_value = ["module.nonexist"] + clean_ref_mock.return_value = ["module.nonexist.output"] get_config_mock.return_value = "nonexist" with self.assertRaises(InvalidResourceLinkingException) as err: @@ -231,7 +239,7 @@ def test_resolve_module_output_raises_exception_empty_children(self, clean_ref_m self.assertEqual( str(err.exception), - "An error occurred when attempting to link two resources: Module module.mymod does not have child modules defined, possible misconfiguration", + "An error occurred when attempting to link two resources: Module module.mymod does not have child modules defined", ) @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") @@ -248,9 +256,32 @@ def test_resolve_module_output_raises_exception_non_exist_child(self, clean_ref_ self.assertEqual( str(err.exception), - "An error occurred when attempting to link two resources: Module module.mymod does not have nonexist as a child module, possible misconfiguration", + "An error occurred when attempting to link two resources: Module module.mymod does not have nonexist as a child module", ) - + + @parameterized.expand( + [ + "module.", + "module..", + "module.....", + "module.name", + "module.name.output.again", + ] + ) + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") + @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._clean_references_list") + def test_resolve_module_output_invalid_module_name(self, invalid_reference, clean_ref_mock, get_config_mock): + module = TFModule("module.name", None, {}, [], {}, {"output1": References([invalid_reference])}) + clean_ref_mock.return_value = [invalid_reference] + + with self.assertRaises(InvalidResourceLinkingException) as err: + _resolve_module_output(module, "output1") + + self.assertEqual( + str(err.exception), + f"An error occurred when attempting to link two resources: Module module.name contains an invalid reference {invalid_reference}", + ) + def test_resolve_module_variable_constant_value(self): constant_value = ConstantValue(value="layer.arn") module = TFModule( From 2210ab5aedce1453c733071af7f40a0b03519339 Mon Sep 17 00:00:00 2001 From: Lucas <12496191+lucashuy@users.noreply.github.com> Date: Thu, 29 Sep 2022 13:21:42 -0700 Subject: [PATCH 5/5] Added check for variable type --- .../terraform/hooks/prepare/test_resource_linking.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py b/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py index 78b76796c5..28d1b7eb1c 100644 --- a/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py +++ b/tests/unit/hook_packages/terraform/hooks/prepare/test_resource_linking.py @@ -165,6 +165,7 @@ def test_resolve_module_output_with_var(self, clean_ref_mock, config_mock, resol # assert we still return valid results self.assertEqual(len(results), 1) self.assertEqual(results[0].value, "mycoolvar") + self.assertIsInstance(results[0], ConstantValue) @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._get_configuration_address") @patch("samcli.hook_packages.terraform.hooks.prepare.resource_linking._clean_references_list")