Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def test_authorizer_apikey(self):
# ApiKeySourceType is AUTHORIZER. Passing api key via x-api-key will not get authorized
self.verify_authorized_request(base_url + "lambda-token-api-key", 401, "x-api-key", key["value"])

@retry(StatusCodeError, 10)
@retry(StatusCodeError, 10, 0.25)
def verify_authorized_request(
self,
url,
Expand Down
2 changes: 1 addition & 1 deletion integration/combination/test_api_with_authorizers.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ def test_authorizers_with_invoke_function_set_none(self):
auth_type_for_api_event_without_auth = api_event_with_out_auth["authorizationType"]
self.assertEqual(auth_type_for_api_event_without_auth, "NONE")

@retry(StatusCodeError, 10)
@retry(StatusCodeError, 10, 0.25)
def verify_authorized_request(
self,
url,
Expand Down
12 changes: 12 additions & 0 deletions integration/combination/test_connectors.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
from time import sleep
from unittest import SkipTest
from parameterized import parameterized
from tenacity import retry, stop_after_attempt, retry_if_exception
from integration.conftest import clean_bucket
from integration.helpers.base_test import S3_BUCKET_PREFIX, BaseTest
from integration.helpers.resource import generate_suffix

retry_once = retry(
stop=stop_after_attempt(2),
# unittest raises SkipTest for skipping tests
retry=retry_if_exception(lambda e: not isinstance(e, SkipTest)),
)


class TestConnectors(BaseTest):
def tearDown(self):
Expand Down Expand Up @@ -41,6 +49,7 @@ def tearDown(self):
("combination/connector_table_to_function_read",),
]
)
@retry_once
def test_connector_by_invoking_a_function(self, template_file_path):
self.skip_using_service_detector(template_file_path)
self.create_and_verify_stack(template_file_path)
Expand Down Expand Up @@ -72,6 +81,7 @@ def test_connector_by_invoking_a_function(self, template_file_path):
("combination/connector_sfn_to_eb_custom_write",),
]
)
@retry_once
def test_connector_by_sync_execute_an_state_machine(self, template_file_path):
self.skip_using_service_detector(template_file_path)
self.create_and_verify_stack(template_file_path)
Expand All @@ -91,6 +101,7 @@ def test_connector_by_sync_execute_an_state_machine(self, template_file_path):
("combination/connector_sfn_to_sfn_sync",),
]
)
@retry_once
def test_connector_by_async_execute_an_state_machine(self, template_file_path):
self.skip_using_service_detector(template_file_path)
self.create_and_verify_stack(template_file_path)
Expand Down Expand Up @@ -123,6 +134,7 @@ def test_connector_by_async_execute_an_state_machine(self, template_file_path):
("combination/connector_bucket_to_function_write",),
]
)
@retry_once
def test_connector_by_execute_a_s3_bucket(self, template_file_path):
self.skip_using_service_detector(template_file_path)
bucket_name = S3_BUCKET_PREFIX + "connector" + generate_suffix()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ def test_custom_http_api_domains_regional(self):
api_gateway_client = self.client_provider.api_v2_client
result = api_gateway_client.get_domain_name(DomainName=domain_name_id)

self.assertEqual("httpapi.sam-gamma-regional.com", result["DomainName"])
if "FeatureToggle" in self.pipeline_prefix:
self.assertEqual("httpapi.ftl.sam-gamma-regional.com", result["DomainName"])
else:
self.assertEqual("httpapi.sam-gamma-regional.com", result["DomainName"])

mtls_auth_config = result["MutualTlsAuthentication"]
self.assertEqual(self.file_to_s3_uri_map["MTLSCert.pem"]["uri"], mtls_auth_config["TruststoreUri"])
Expand Down
12 changes: 10 additions & 2 deletions integration/combination/test_custom_rest_api_domains.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@
class TestCustomRestApiDomains(BaseInternalTest):
def test_custom_rest_api_domains_edge(self):
self.create_and_verify_stack("combination/api_with_custom_domains_edge")

domain_name_list = self.get_stack_resources("AWS::ApiGateway::DomainName")
self.assertEqual(1, len(domain_name_list))

domain_name_id = self.get_physical_id_by_type("AWS::ApiGateway::DomainName")
api_gateway_client = self.client_provider.api_client
result = api_gateway_client.get_domain_name(domainName=domain_name_id)

self.assertEqual("sam-gamma-edge.com", result["domainName"])
if "FeatureToggle" in self.pipeline_prefix:
self.assertEqual("ftl.sam-gamma-edge.com", result["domainName"])
else:
self.assertEqual("sam-gamma-edge.com", result["domainName"])

end_point_config = result["endpointConfiguration"]
end_point_types = end_point_config["types"]
Expand All @@ -37,7 +41,11 @@ def test_custom_rest_api_domains_regional(self):
api_gateway_client = self.client_provider.api_client
result = api_gateway_client.get_domain_name(domainName=domain_name_id)

self.assertEqual("sam-gamma-regional.com", result["domainName"])
if "FeatureToggle" in self.pipeline_prefix:
self.assertEqual("ftl.sam-gamma-regional.com", result["domainName"])
else:
self.assertEqual("sam-gamma-regional.com", result["domainName"])

self.assertEqual("TLS_1_2", result["securityPolicy"])

end_point_config = result["endpointConfiguration"]
Expand Down
30 changes: 30 additions & 0 deletions integration/conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import time
import boto3
import botocore
import pytest
Expand Down Expand Up @@ -63,6 +64,26 @@ def clean_all_integ_buckets():
clean_bucket(bucket.name, s3_client)


def _delete_unused_network_interface_by_subnet(ec2_client, subnet_id):
"""Deletes unused network interface under the provided subnet"""
paginator = ec2_client.get_paginator("describe_network_interfaces")
response_iterator = paginator.paginate(
Filters=[
{"Name": "subnet-id", "Values": [subnet_id]},
{"Name": "status", "Values": ["available"]},
]
)
network_interface_ids = []
for page in response_iterator:
network_interface_ids += [ni["NetworkInterfaceId"] for ni in page["NetworkInterfaces"]]

for ni_id in network_interface_ids:
ec2_client.delete_network_interface(NetworkInterfaceId=ni_id)
time.sleep(0.5)

LOG.info("Deleted %s unused network interfaces under subnet %s", len(network_interface_ids), subnet_id)


@pytest.fixture()
def setup_companion_stack_once(tmpdir_factory, get_prefix):
tests_integ_dir = Path(__file__).resolve().parents[1]
Expand All @@ -74,6 +95,15 @@ def setup_companion_stack_once(tmpdir_factory, get_prefix):
companion_stack = Stack(stack_name, companion_stack_tempalte_path, cfn_client, output_dir)
companion_stack.create_or_update(_stack_exists(stack_name))

ec2_client = ClientProvider().ec2_client
precreated_subnet_ids = [
resource["PhysicalResourceId"]
for resource in companion_stack.stack_resources["StackResourceSummaries"]
if resource["LogicalResourceId"].startswith("PreCreatedSubnet")
]
for subnet_id in precreated_subnet_ids:
_delete_unused_network_interface_by_subnet(ec2_client, subnet_id)


@pytest.fixture()
def get_serverless_application_repository_app():
Expand Down
18 changes: 16 additions & 2 deletions integration/helpers/base_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@

STACK_NAME_PREFIX = "sam-integ-stack-"
S3_BUCKET_PREFIX = "sam-integ-bucket-"
FEATURE_TOGGLE_JSON_FILES = [
"http_api_with_custom_domains_regional",
"http_api_with_custom_domains_regional_ownership_verification",
"api_with_custom_domains_edge",
"api_with_custom_domains_regional",
"api_with_custom_domains_regional_ownership_verification",
]


class BaseTest(TestCase):
Expand Down Expand Up @@ -154,13 +161,20 @@ def create_and_verify_stack(self, file_path, parameters=None, s3_uploader=None):
s3_uploader: S3Uploader object
Object for uploading files to s3
"""
folder, file_name = file_path.split("/")

# If template is too large, calling the method with self.s3_uploader to send the template to s3 then deploy
self.create_stack(file_path, parameters, s3_uploader)
self.expected_resource_path = str(Path(self.expected_dir, folder, file_name + ".json"))
self.get_expected_json_file_name(file_path)
self.verify_stack()

def get_expected_json_file_name(self, file_path):
folder, file_name = file_path.split("/")

if "FeatureToggle" in self.pipeline_prefix and file_name in FEATURE_TOGGLE_JSON_FILES:
self.expected_resource_path = str(Path(self.expected_dir, folder, file_name + "_feature_toggle.json"))
else:
self.expected_resource_path = str(Path(self.expected_dir, folder, file_name + ".json"))

def skip_using_service_detector(self, file_path):
"""
Skips the test if it cannot pass the test of
Expand Down
11 changes: 11 additions & 0 deletions integration/helpers/client_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def __init__(self):
self._kafka_client = None
self._code_deploy_client = None
self._sar_client = None
self._ec2_client = None

@property
def cfn_client(self):
Expand Down Expand Up @@ -216,3 +217,13 @@ def sar_client(self):
if not self._sar_client:
self._sar_client = boto3.client("serverlessrepo")
return self._sar_client

@property
def ec2_client(self):
"""
EC2 Client
"""
with self._lock:
if not self._ec2_client:
self._ec2_client = boto3.client("ec2")
return self._ec2_client
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[
{ "LogicalResourceId":"RecordSetGroupc911be5759", "ResourceType":"AWS::Route53::RecordSetGroup" },
{ "LogicalResourceId":"MyApiDeployment", "ResourceType":"AWS::ApiGateway::Deployment" },
{ "LogicalResourceId":"ApiGatewayDomainName299fac327d", "ResourceType":"AWS::ApiGateway::DomainName" },
{ "LogicalResourceId":"MyApi", "ResourceType":"AWS::ApiGateway::RestApi" },
{ "LogicalResourceId":"MyApiProdStage", "ResourceType":"AWS::ApiGateway::Stage" },
{ "LogicalResourceId":"MyFunction", "ResourceType":"AWS::Lambda::Function" },
{ "LogicalResourceId":"MyFunctionRole", "ResourceType":"AWS::IAM::Role" },
{ "LogicalResourceId":"MyApigetBasePathMapping", "ResourceType":"AWS::ApiGateway::BasePathMapping" },
{ "LogicalResourceId":"MyFunctionFetchPermissionProd", "ResourceType":"AWS::Lambda::Permission" }
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{ "LogicalResourceId":"MyFunctionImplicitGetPermissionProd", "ResourceType":"AWS::Lambda::Permission" },
{ "LogicalResourceId":"ServerlessRestApiDeployment", "ResourceType":"AWS::ApiGateway::Deployment" },
{ "LogicalResourceId":"ServerlessRestApipostBasePathMapping", "ResourceType":"AWS::ApiGateway::BasePathMapping" },
{ "LogicalResourceId":"ServerlessRestApi", "ResourceType":"AWS::ApiGateway::RestApi" },
{ "LogicalResourceId":"RecordSetGroupd17dced08c", "ResourceType":"AWS::Route53::RecordSetGroup" },
{ "LogicalResourceId":"ServerlessRestApiProdStage", "ResourceType":"AWS::ApiGateway::Stage" },
{ "LogicalResourceId":"ServerlessRestApigetBasePathMapping", "ResourceType":"AWS::ApiGateway::BasePathMapping" },
{ "LogicalResourceId":"ApiGatewayDomainName98c928338d", "ResourceType":"AWS::ApiGateway::DomainName" },
{ "LogicalResourceId":"MyFunction", "ResourceType":"AWS::Lambda::Function" },
{ "LogicalResourceId":"MyFunctionImplicitPostPermissionProd", "ResourceType":"AWS::Lambda::Permission" },
{ "LogicalResourceId":"MyFunctionRole", "ResourceType":"AWS::IAM::Role" }
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{ "LogicalResourceId":"MyFunctionImplicitGetPermissionProd", "ResourceType":"AWS::Lambda::Permission" },
{ "LogicalResourceId":"ServerlessRestApiDeployment", "ResourceType":"AWS::ApiGateway::Deployment" },
{ "LogicalResourceId":"ServerlessRestApipostBasePathMapping", "ResourceType":"AWS::ApiGateway::BasePathMapping" },
{ "LogicalResourceId":"ServerlessRestApi", "ResourceType":"AWS::ApiGateway::RestApi" },
{ "LogicalResourceId":"RecordSetGroupd17dced08c", "ResourceType":"AWS::Route53::RecordSetGroup" },
{ "LogicalResourceId":"ServerlessRestApiProdStage", "ResourceType":"AWS::ApiGateway::Stage" },
{ "LogicalResourceId":"ServerlessRestApigetBasePathMapping", "ResourceType":"AWS::ApiGateway::BasePathMapping" },
{ "LogicalResourceId":"ApiGatewayDomainNamef593820b0b", "ResourceType":"AWS::ApiGateway::DomainName" },
{ "LogicalResourceId":"MyFunction", "ResourceType":"AWS::Lambda::Function" },
{ "LogicalResourceId":"MyFunctionImplicitPostPermissionProd", "ResourceType":"AWS::Lambda::Permission" },
{ "LogicalResourceId":"MyFunctionRole", "ResourceType":"AWS::IAM::Role" }
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{ "LogicalResourceId":"MyFunctionImplicitGetPermission", "ResourceType":"AWS::Lambda::Permission" },
{ "LogicalResourceId":"MyFunctionImplicitPostPermission", "ResourceType":"AWS::Lambda::Permission" },
{ "LogicalResourceId":"MyApipostApiMapping", "ResourceType":"AWS::ApiGatewayV2::ApiMapping" },
{ "LogicalResourceId":"MyApigetApiMapping", "ResourceType":"AWS::ApiGatewayV2::ApiMapping" },
{ "LogicalResourceId":"MyApi", "ResourceType":"AWS::ApiGatewayV2::Api" },
{ "LogicalResourceId":"RecordSetGroupd17dced08c", "ResourceType":"AWS::Route53::RecordSetGroup" },
{ "LogicalResourceId":"MyApiProdStage", "ResourceType":"AWS::ApiGatewayV2::Stage" },
{ "LogicalResourceId":"ApiGatewayDomainNameV26198c55d75", "ResourceType":"AWS::ApiGatewayV2::DomainName" },
{ "LogicalResourceId":"MyFunction", "ResourceType":"AWS::Lambda::Function" },
{ "LogicalResourceId":"MyFunctionRole", "ResourceType":"AWS::IAM::Role" }
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{ "LogicalResourceId":"MyFunctionImplicitGetPermission", "ResourceType":"AWS::Lambda::Permission" },
{ "LogicalResourceId":"MyFunctionImplicitPostPermission", "ResourceType":"AWS::Lambda::Permission" },
{ "LogicalResourceId":"MyApipostApiMapping", "ResourceType":"AWS::ApiGatewayV2::ApiMapping" },
{ "LogicalResourceId":"MyApigetApiMapping", "ResourceType":"AWS::ApiGatewayV2::ApiMapping" },
{ "LogicalResourceId":"MyApi", "ResourceType":"AWS::ApiGatewayV2::Api" },
{ "LogicalResourceId":"RecordSetGroupd17dced08c", "ResourceType":"AWS::Route53::RecordSetGroup" },
{ "LogicalResourceId":"MyApiProdStage", "ResourceType":"AWS::ApiGatewayV2::Stage" },
{ "LogicalResourceId":"ApiGatewayDomainNameV2483cac8ea6", "ResourceType":"AWS::ApiGatewayV2::DomainName" },
{ "LogicalResourceId":"MyFunction", "ResourceType":"AWS::Lambda::Function" },
{ "LogicalResourceId":"MyFunctionRole", "ResourceType":"AWS::IAM::Role" }
]
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ Parameters:
Type: String
MyEdgeDomainCert:
Type: String
HostedZoneId:
Type: String

Resources:
MyFunction:
Expand Down Expand Up @@ -41,5 +43,6 @@ Resources:
BasePath:
- /get
Route53:
HostedZoneId: Z1SKZDMQ2UR7IW
HostedZoneId:
Ref: HostedZoneId
IpV6: true
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ Parameters:
Type: String
MyRestRegionalDomainCert:
Type: String
HostedZoneId:
Type: String

Globals:
Api:
Expand All @@ -20,7 +22,8 @@ Globals:
- /get
- /post
Route53:
HostedZoneId: Z1DTV8GVAVOHDR
HostedZoneId:
Ref: HostedZoneId

Resources:
MyFunction:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ Parameters:
Type: String
MyDomainOwnershipVerificationCertificate:
Type: String
HostedZoneId:
Type: String

Globals:
Api:
Expand All @@ -22,7 +24,8 @@ Globals:
- /get
- /post
Route53:
HostedZoneId: Z1DTV8GVAVOHDR
HostedZoneId:
Ref: HostedZoneId
OwnershipVerificationCertificateArn:
Ref: MyDomainOwnershipVerificationCertificate

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Resources:
TriggerFunction:
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs16.x
Runtime: nodejs14.x
Handler: index.handler
Timeout: 10 # in case eb has delay
InlineCode: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Resources:
TriggerFunction:
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs16.x
Runtime: nodejs14.x
Handler: index.handler
Timeout: 10 # in case eb has delay
InlineCode: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Resources:
TriggerFunction:
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs16.x
Runtime: nodejs14.x
Handler: index.handler
Timeout: 10 # in case eb has delay
InlineCode: |
Expand Down Expand Up @@ -52,7 +52,7 @@ Resources:
Function:
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs16.x
Runtime: nodejs14.x
Handler: index.handler
InlineCode: |
const AWS = require('aws-sdk');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Resources:
TriggerFunction:
Type: AWS::Serverless::Function
Properties:
Runtime: nodejs16.x
Runtime: nodejs14.x
Handler: index.handler
Timeout: 10 # in case eb has delay
InlineCode: |
Expand Down
Loading