Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fix build and deploy SAR integration test cases #5244

Merged
merged 4 commits into from
Jun 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion samcli/commands/remote_invoke/remote_invoke_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@


class RemoteInvokeContext:

_boto_client_provider: BotoProviderType
_boto_resource_provider: BotoProviderType
_stack_name: Optional[str]
Expand Down
15 changes: 15 additions & 0 deletions tests/integration/buildcmd/test_build_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
SKIP_DOCKER_BUILD,
SKIP_DOCKER_MESSAGE,
run_command_with_input,
UpdatableSARTemplate,
)
from .build_integ_base import (
BuildIntegBase,
Expand Down Expand Up @@ -2959,6 +2960,20 @@ def test_functions_layers_with_s3_codeuri(self):
class TestBuildSAR(BuildIntegBase):
template = "aws-serverless-application-with-application-id-map.yaml"

@classmethod
def setUpClass(cls):
super(TestBuildSAR, cls).setUpClass()
cls.update_sar_template = None
if cls.template_path:
cls.update_sar_template = UpdatableSARTemplate(cls.template_path)
cls.update_sar_template.setup()
cls.template_path = cls.update_sar_template.updated_template_path

@classmethod
def tearDownClass(cls):
if cls.update_sar_template:
cls.update_sar_template.clean()

@parameterized.expand(
[
("use_container", "us-east-2"),
Expand Down
70 changes: 38 additions & 32 deletions tests/integration/deploy/test_deploy_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from samcli.lib.bootstrap.bootstrap import SAM_CLI_STACK_NAME
from samcli.lib.config.samconfig import DEFAULT_CONFIG_FILE_NAME
from tests.integration.deploy.deploy_integ_base import DeployIntegBase
from tests.testing_utils import RUNNING_ON_CI, RUNNING_TEST_FOR_MASTER_ON_CI, RUN_BY_CANARY
from tests.testing_utils import RUNNING_ON_CI, RUNNING_TEST_FOR_MASTER_ON_CI, RUN_BY_CANARY, UpdatableSARTemplate

# Deploy tests require credentials and CI/CD will only add credentials to the env if the PR is from the same repo.
# This is to restrict package tests to run outside of CI/CD, when the branch is not master or tests are not run by Canary
Expand Down Expand Up @@ -888,25 +888,28 @@ def test_deploy_with_code_signing_params(self, should_sign, should_enforce, will
]
)
def test_deploy_sar_with_location_from_map(self, template_file, region, will_succeed):
template_path = Path(__file__).resolve().parents[1].joinpath("testdata", "buildcmd", template_file)
stack_name = self._method_to_stack_name(self.id())
self.stacks.append({"name": stack_name, "region": region})
with UpdatableSARTemplate(
Path(__file__).resolve().parents[1].joinpath("testdata", "buildcmd", template_file)
) as sar_app:
template_path = sar_app.updated_template_path
stack_name = self._method_to_stack_name(self.id())
self.stacks.append({"name": stack_name, "region": region})

# The default region (us-east-1) has no entry in the map
deploy_command_list = self.get_deploy_command_list(
template_file=template_path,
s3_prefix=self.s3_prefix,
stack_name=stack_name,
capabilities_list=["CAPABILITY_IAM", "CAPABILITY_AUTO_EXPAND"],
region=region, # the !FindInMap has an entry for use-east-2 region only
)
deploy_process_execute = self.run_command(deploy_command_list)
# The default region (us-east-1) has no entry in the map
deploy_command_list = self.get_deploy_command_list(
template_file=template_path,
s3_prefix=self.s3_prefix,
stack_name=stack_name,
capabilities_list=["CAPABILITY_IAM", "CAPABILITY_AUTO_EXPAND"],
region=region, # the !FindInMap has an entry for use-east-2 region only
)
deploy_process_execute = self.run_command(deploy_command_list)

if will_succeed:
self.assertEqual(deploy_process_execute.process.returncode, 0)
else:
self.assertEqual(deploy_process_execute.process.returncode, 1)
self.assertIn("Property \\'ApplicationId\\' cannot be resolved.", str(deploy_process_execute.stderr))
if will_succeed:
self.assertEqual(deploy_process_execute.process.returncode, 0)
else:
self.assertEqual(deploy_process_execute.process.returncode, 1)
self.assertIn("Property \\'ApplicationId\\' cannot be resolved.", str(deploy_process_execute.stderr))

@parameterized.expand(
[
Expand All @@ -915,23 +918,26 @@ def test_deploy_sar_with_location_from_map(self, template_file, region, will_suc
]
)
def test_deploy_guided_sar_with_location_from_map(self, template_file, region, will_succeed):
template_path = Path(__file__).resolve().parents[1].joinpath("testdata", "buildcmd", template_file)
stack_name = self._method_to_stack_name(self.id())
self.stacks.append({"name": stack_name, "region": region})
with UpdatableSARTemplate(
Path(__file__).resolve().parents[1].joinpath("testdata", "buildcmd", template_file)
) as sar_app:
template_path = sar_app.updated_template_path
stack_name = self._method_to_stack_name(self.id())
self.stacks.append({"name": stack_name, "region": region})

# Package and Deploy in one go without confirming change set.
deploy_command_list = self.get_deploy_command_list(template_file=template_path, guided=True)
# Package and Deploy in one go without confirming change set.
deploy_command_list = self.get_deploy_command_list(template_file=template_path, guided=True)

deploy_process_execute = self.run_command_with_input(
deploy_command_list,
f"{stack_name}\n{region}\n\nN\nCAPABILITY_IAM CAPABILITY_AUTO_EXPAND\nn\nN\n".encode(),
)
deploy_process_execute = self.run_command_with_input(
deploy_command_list,
f"{stack_name}\n{region}\n\nN\nCAPABILITY_IAM CAPABILITY_AUTO_EXPAND\nn\nN\n".encode(),
)

if will_succeed:
self.assertEqual(deploy_process_execute.process.returncode, 0)
else:
self.assertEqual(deploy_process_execute.process.returncode, 1)
self.assertIn("Property \\'ApplicationId\\' cannot be resolved.", str(deploy_process_execute.stderr))
if will_succeed:
self.assertEqual(deploy_process_execute.process.returncode, 0)
else:
self.assertEqual(deploy_process_execute.process.returncode, 1)
self.assertIn("Property \\'ApplicationId\\' cannot be resolved.", str(deploy_process_execute.stderr))

@parameterized.expand(
[os.path.join("deep-nested", "template.yaml"), os.path.join("deep-nested-image", "template.yaml")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ Transform: AWS::Serverless-2016-10-31
Mappings:
MappingExample:
us-east-2:
ApplicationId: !Sub arn:aws:serverlessrepo:us-east-1:${AWS::AccountId}:applications/sam-cli-integration-test-sar-app
ApplicationId: arn:aws:serverlessrepo:us-east-1:${AWS::AccountId}:applications/shared-sam-cli-integration-test-sar-app

Resources:
MyApplication:
Type: AWS::Serverless::Application
Properties:
Location:
ApplicationId: !FindInMap [ MappingExample, !Ref AWS::Region, ApplicationId ]
SemanticVersion: 1.0.4
Parameters:
IdentityNameParameter: AnyValue
SemanticVersion: 1.0.4
41 changes: 41 additions & 0 deletions tests/testing_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import platform
import subprocess
import tempfile
from pathlib import Path

from threading import Thread
from typing import Callable, List, Optional
Expand All @@ -13,6 +14,7 @@
import shutil
from uuid import uuid4

import boto3
import psutil

RUNNING_ON_APPVEYOR = os.environ.get("APPVEYOR", False)
Expand Down Expand Up @@ -232,3 +234,42 @@ def full_path(self, filename):
f.full_path('foo/bar.txt') -> /tmp/asdfasd/foo/bar.txt
"""
return os.path.join(self.rootdir, filename)


def _get_current_account_id():
sts = boto3.client("sts")
account_id = sts.get_caller_identity()["Account"]
return account_id


class UpdatableSARTemplate:
"""
This class is used to replace the `${AWS::AccountId}` in the testing templates with the account id for the testing
is used during the integration testing. This class helps to resolve the problem that SAM CLI does not support Sub
intrinsic function, and to avoid exposing any of our testing accounts ids.
"""

def __init__(self, source_template_path):
self.source_template_path = source_template_path
self.temp_directory = tempfile.TemporaryDirectory()
self.temp_directory_path = Path(tempfile.TemporaryDirectory().name)
self.updated_template_path = None

def setup(self):
with open(self.source_template_path, "r") as sar_template:
updated_template_content = sar_template.read()
updated_template_content = updated_template_content.replace("${AWS::AccountId}", _get_current_account_id())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my understanding (I can't see the test failure logs for some reason) why do we need to do this manually instead of letting the intrinsic sub handle it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue we do not support Sub intrinsic function :( .. This is the error we got in the canaries:

Error: [InvalidResourceException('MyApplication', "Property 'ApplicationId' cannot be resolved. Only FindInMap and Ref intrinsic functions are supported.")] ('MyApplication', "Property 'ApplicationId' cannot be resolved. Only FindInMap and Ref intrinsic functions are supported.")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a comment about this so we won't revert it by mistake in the future?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

self.temp_directory_path.mkdir()
self.updated_template_path = os.path.join(self.temp_directory_path, "template.yml")
with open(self.updated_template_path, "w") as updated_template:
updated_template.write(updated_template_content)

def clean(self):
self.temp_directory.cleanup()

def __enter__(self):
self.setup()
return self

def __exit__(self, *args):
self.clean()