diff --git a/tests/integration/buildcmd/build_integ_base.py b/tests/integration/buildcmd/build_integ_base.py index 2dab556843..9c22e11192 100644 --- a/tests/integration/buildcmd/build_integ_base.py +++ b/tests/integration/buildcmd/build_integ_base.py @@ -84,6 +84,7 @@ def get_command_list( build_in_source=None, mount_with=None, config_file=None, + project_root_dir=None, ): command_list = [self.cmd, "build"] @@ -150,6 +151,9 @@ def get_command_list( if config_file is not None: command_list += ["--config-file", config_file] + if project_root_dir is not None: + command_list += ["--terraform-project-root-path", project_root_dir] + return command_list def verify_docker_container_cleanedup(self, runtime): diff --git a/tests/integration/buildcmd/test_build_terraform_applications_other_cases.py b/tests/integration/buildcmd/test_build_terraform_applications_other_cases.py index 2320fa0737..e9282013d8 100644 --- a/tests/integration/buildcmd/test_build_terraform_applications_other_cases.py +++ b/tests/integration/buildcmd/test_build_terraform_applications_other_cases.py @@ -6,6 +6,7 @@ from parameterized import parameterized, parameterized_class +from samcli.lib.utils.colors import Colored from tests.integration.buildcmd.test_build_terraform_applications import ( BuildTerraformApplicationIntegBase, BuildTerraformApplicationS3BackendIntegBase, @@ -52,6 +53,27 @@ def test_exit_failed_use_container_no_build_image_hooks(self): ) self.assertNotEqual(return_code, 0) + def test_exit_failed_project_root_dir_no_hooks(self): + cmdlist = self.get_command_list(beta_features=True, project_root_dir="/path") + _, stderr, return_code = self.run_command(cmdlist) + process_stderr = stderr.strip() + self.assertRegex( + process_stderr.decode("utf-8"), + "Error: Missing option --hook-name", + ) + self.assertNotEqual(return_code, 0) + + def test_exit_failed_project_root_dir_not_parent_of_current_directory(self): + cmdlist = self.get_command_list(beta_features=True, hook_name="terraform", project_root_dir="/path") + _, stderr, return_code = self.run_command(cmdlist) + process_stderr = stderr.strip() + self.assertRegex( + process_stderr.decode("utf-8"), + "Error: /path is not a valid value for Terraform Project Root Path. It should " + "be a parent of the current directory that contains the root module of the terraform project.", + ) + self.assertNotEqual(return_code, 0) + def test_exit_failed_use_container_short_format_no_build_image_hooks(self): cmdlist = self.get_command_list(beta_features=True, hook_name="terraform") cmdlist += ["-u"] @@ -384,3 +406,60 @@ def test_invoke_function(self): overrides=None, expected_result="{'message': 'Hello World'}", ) + + +@skipIf( + (not RUN_BY_CANARY and not CI_OVERRIDE), + "Skip Terraform test cases unless running in CI", +) +class TestBuildTerraformApplicationsSourceCodeAndModulesAreNotInRootModuleDirectory(BuildTerraformApplicationIntegBase): + terraform_application = Path("terraform/application_outside_root_directory") + + functions = [ + ("aws_lambda_function.function1", "hello world 1"), + ("module.function2.aws_lambda_function.this", "hello world 1"), + ("module.function7.aws_lambda_function.this[0]", "hello world 1"), + ] + + def setUp(self): + super().setUp() + self.project_dir = self.working_dir + self.working_dir = f"{self.working_dir}/root_module" + + def tearDown(self): + if self.project_dir: + self.working_dir = self.project_dir + super().tearDown() + + @parameterized.expand(functions) + def test_build_and_invoke_lambda_functions(self, function_identifier, expected_output): + command_list_parameters = { + "beta_features": True, + "hook_name": "terraform", + "function_identifier": function_identifier, + "project_root_dir": "./..", + } + build_cmd_list = self.get_command_list(**command_list_parameters) + LOG.info("command list: %s", build_cmd_list) + stdout, stderr, return_code = self.run_command(build_cmd_list) + terraform_beta_feature_prompted_text = ( + f"Supporting Terraform applications is a beta feature.{os.linesep}" + f"Please confirm if you would like to proceed using AWS SAM CLI with terraform application.{os.linesep}" + "You can also enable this beta feature with 'sam build --beta-features'." + ) + experimental_warning = ( + f"{os.linesep}Experimental features are enabled for this session.{os.linesep}" + f"Visit the docs page to learn more about the AWS Beta terms " + f"https://aws.amazon.com/service-terms/.{os.linesep}" + ) + self.assertNotRegex(stdout.decode("utf-8"), terraform_beta_feature_prompted_text) + self.assertIn(Colored().yellow(experimental_warning), stderr.decode("utf-8")) + LOG.info("sam build stdout: %s", stdout.decode("utf-8")) + LOG.info("sam build stderr: %s", stderr.decode("utf-8")) + self.assertEqual(return_code, 0) + + self._verify_invoke_built_function( + function_logical_id=function_identifier, + overrides=None, + expected_result={"statusCode": 200, "body": expected_output}, + ) diff --git a/tests/integration/testdata/buildcmd/terraform/application_outside_root_directory/modules/lambda_function/main.tf b/tests/integration/testdata/buildcmd/terraform/application_outside_root_directory/modules/lambda_function/main.tf new file mode 100644 index 0000000000..0200f69dfe --- /dev/null +++ b/tests/integration/testdata/buildcmd/terraform/application_outside_root_directory/modules/lambda_function/main.tf @@ -0,0 +1,42 @@ +variable "source_code" { + type = string +} + +variable "function_name" { + type = string +} + +variable "layers" { + type = list + default = [] +} + +resource "aws_iam_role" "iam_for_lambda" { + name = "iam_for_lambda2" + + assume_role_policy = <