Skip to content

Commit

Permalink
Merge release-v1.48.0 into main
Browse files Browse the repository at this point in the history
  • Loading branch information
aws-sam-cli-bot authored Jul 25, 2022
2 parents 6b0afc5 + a1dead3 commit 4c3f5f8
Show file tree
Hide file tree
Showing 77 changed files with 4,508 additions and 563 deletions.
8 changes: 8 additions & 0 deletions INTEGRATION_TESTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ If you haven't done so already, run the following command in a terminal at the r
make init
```

### Setting up a companion stack

To run the tests, a companion stack first needs to be created. This stack houses some resources that are required by the tests, such as an S3 bucket.

```
make prepare-companion-stack
```

### Running all the tests

From the root of the repository, run:
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ lint:
# Linter performs static analysis to catch latent bugs
pylint --rcfile .pylintrc samtranslator

prepare-companion-stack:
pytest -v --no-cov integration/setup -m setup

# Command to run everytime you make changes to verify everything works
dev: test

Expand All @@ -43,5 +46,6 @@ TARGETS
integ-test Run the Integration tests.
dev Run all development tests after a change.
pr Perform all checks before submitting a Pull Request.
prepare-companion-stack Create or update the companion stack for running integration tests.

endef
5 changes: 5 additions & 0 deletions integration/combination/test_api_settings.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import hashlib
from unittest.case import skipIf

from integration.helpers.resource import current_region_does_not_support
from integration.config.service_names import REST_API

try:
from pathlib import Path
Expand All @@ -10,6 +14,7 @@
from integration.helpers.base_test import BaseTest


@skipIf(current_region_does_not_support([REST_API]), "Rest API is not supported in this testing region")
class TestApiSettings(BaseTest):
def test_method_settings(self):
self.create_and_verify_stack("combination/api_with_method_settings")
Expand Down
36 changes: 17 additions & 19 deletions integration/combination/test_api_with_cors.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
from integration.helpers.base_test import BaseTest
import requests
from unittest.case import skipIf

from integration.helpers.base_test import BaseTest
from integration.helpers.resource import current_region_does_not_support
from integration.config.service_names import REST_API
from integration.helpers.deployer.utils.retry import retry
from parameterized import parameterized

from integration.helpers.exception import StatusCodeError

ALL_METHODS = "DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT"


@skipIf(current_region_does_not_support([REST_API]), "Rest API is not supported in this testing region")
class TestApiWithCors(BaseTest):
@parameterized.expand(
[
Expand All @@ -26,8 +29,8 @@ def test_cors(self, file_name):
allow_headers = "headers"
max_age = "600"

self.verify_options_request(base_url + "/apione", allow_methods, allow_origin, allow_headers, max_age)
self.verify_options_request(base_url + "/apitwo", allow_methods, allow_origin, allow_headers, max_age)
self.verify_cors_options_request(base_url + "/apione", allow_methods, allow_origin, allow_headers, max_age)
self.verify_cors_options_request(base_url + "/apitwo", allow_methods, allow_origin, allow_headers, max_age)

def test_cors_with_shorthand_notation(self):
self.create_and_verify_stack("combination/api_with_cors_shorthand")
Expand All @@ -38,8 +41,8 @@ def test_cors_with_shorthand_notation(self):
allow_headers = None # This should be absent from response
max_age = None # This should be absent from response

self.verify_options_request(base_url + "/apione", ALL_METHODS, allow_origin, allow_headers, max_age)
self.verify_options_request(base_url + "/apitwo", "OPTIONS,POST", allow_origin, allow_headers, max_age)
self.verify_cors_options_request(base_url + "/apione", ALL_METHODS, allow_origin, allow_headers, max_age)
self.verify_cors_options_request(base_url + "/apitwo", "OPTIONS,POST", allow_origin, allow_headers, max_age)

def test_cors_with_only_methods(self):
self.create_and_verify_stack("combination/api_with_cors_only_methods")
Expand All @@ -51,8 +54,8 @@ def test_cors_with_only_methods(self):
allow_headers = None # This should be absent from response
max_age = None # This should be absent from response

self.verify_options_request(base_url + "/apione", allow_methods, allow_origin, allow_headers, max_age)
self.verify_options_request(base_url + "/apitwo", allow_methods, allow_origin, allow_headers, max_age)
self.verify_cors_options_request(base_url + "/apione", allow_methods, allow_origin, allow_headers, max_age)
self.verify_cors_options_request(base_url + "/apitwo", allow_methods, allow_origin, allow_headers, max_age)

def test_cors_with_only_headers(self):
self.create_and_verify_stack("combination/api_with_cors_only_headers")
Expand All @@ -63,8 +66,8 @@ def test_cors_with_only_headers(self):
allow_headers = "headers"
max_age = None # This should be absent from response

self.verify_options_request(base_url + "/apione", ALL_METHODS, allow_origin, allow_headers, max_age)
self.verify_options_request(base_url + "/apitwo", "OPTIONS,POST", allow_origin, allow_headers, max_age)
self.verify_cors_options_request(base_url + "/apione", ALL_METHODS, allow_origin, allow_headers, max_age)
self.verify_cors_options_request(base_url + "/apitwo", "OPTIONS,POST", allow_origin, allow_headers, max_age)

def test_cors_with_only_max_age(self):
self.create_and_verify_stack("combination/api_with_cors_only_max_age")
Expand All @@ -75,17 +78,12 @@ def test_cors_with_only_max_age(self):
allow_headers = None
max_age = "600"

self.verify_options_request(base_url + "/apione", ALL_METHODS, allow_origin, allow_headers, max_age)
self.verify_options_request(base_url + "/apitwo", "OPTIONS,POST", allow_origin, allow_headers, max_age)
self.verify_cors_options_request(base_url + "/apione", ALL_METHODS, allow_origin, allow_headers, max_age)
self.verify_cors_options_request(base_url + "/apitwo", "OPTIONS,POST", allow_origin, allow_headers, max_age)

@retry(StatusCodeError, 3)
def verify_options_request(self, url, allow_methods, allow_origin, allow_headers, max_age):
response = requests.options(url)
status = response.status_code
if status != 200:
raise StatusCodeError("Request to {} failed with status: {}, expected status: 200".format(url, status))
def verify_cors_options_request(self, url, allow_methods, allow_origin, allow_headers, max_age):
response = self.verify_options_request(url, 200)

self.assertEqual(status, 200, "Options request must be successful and return HTTP 200")
headers = response.headers
self.assertEqual(
headers.get("Access-Control-Allow-Methods"), allow_methods, "Allow-Methods header must have proper value"
Expand Down
29 changes: 29 additions & 0 deletions integration/combination/test_api_with_fail_on_warnings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from parameterized import parameterized

from integration.helpers.base_test import BaseTest


class TestApiWithFailOnWarnings(BaseTest):
@parameterized.expand(
[
("combination/api_with_fail_on_warnings", True),
("combination/api_with_fail_on_warnings", False),
]
)
def test_end_point_configuration(self, file_name, disable_value):
parameters = [
{
"ParameterKey": "FailOnWarningsValue",
"ParameterValue": "true" if disable_value else "false",
"UsePreviousValue": False,
"ResolvedValue": "string",
}
]

self.create_and_verify_stack(file_name, parameters)

rest_api_id = self.get_physical_id_by_type("AWS::ApiGateway::RestApi")
apigw_client = self.client_provider.api_client

api_result = apigw_client.get_rest_api(restApiId=rest_api_id)
self.assertEqual(api_result["ResponseMetadata"]["HTTPStatusCode"], 200)
14 changes: 12 additions & 2 deletions integration/combination/test_api_with_gateway_responses.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import logging
from unittest.case import skipIf

from tenacity import stop_after_attempt, retry_if_exception_type, after_log, wait_exponential, retry, wait_random

from integration.helpers.base_test import BaseTest
from integration.helpers.deployer.utils.retry import retry
from integration.helpers.resource import current_region_does_not_support
from integration.config.service_names import GATEWAY_RESPONSES

LOG = logging.getLogger(__name__)


@skipIf(
current_region_does_not_support([GATEWAY_RESPONSES]), "GatewayResponses is not supported in this testing region"
Expand Down Expand Up @@ -33,7 +37,13 @@ def test_gateway_responses(self):
base_url = stack_outputs["ApiUrl"]
self._verify_request_response_and_cors(base_url + "iam", 403)

@retry(AssertionError, exc_raise=AssertionError, exc_raise_msg="Unable to verify GatewayResponse request.")
@retry(
stop=stop_after_attempt(5),
wait=wait_exponential(multiplier=1, min=4, max=10) + wait_random(0, 1),
retry=retry_if_exception_type(AssertionError),
after=after_log(LOG, logging.WARNING),
reraise=True,
)
def _verify_request_response_and_cors(self, url, expected_response):
response = self.verify_get_request_response(url, expected_response)
access_control_allow_origin = response.headers.get("Access-Control-Allow-Origin", "")
Expand Down
4 changes: 4 additions & 0 deletions integration/combination/test_api_with_resource_policies.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import json
from unittest.case import skipIf

from integration.helpers.base_test import BaseTest
from integration.helpers.resource import current_region_does_not_support
from integration.config.service_names import REST_API


@skipIf(current_region_does_not_support([REST_API]), "Rest API is not supported in this testing region")
class TestApiWithResourcePolicies(BaseTest):
def test_api_resource_policies(self):
self.create_and_verify_stack("combination/api_with_resource_policies")
Expand Down
3 changes: 1 addition & 2 deletions integration/combination/test_custom_http_api_domains_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from integration.config.service_names import CUSTOM_DOMAIN
from integration.helpers.base_internal_test import BaseInternalTest
from integration.helpers.file_resources import FILE_TO_S3_URI_MAP
from integration.helpers.resource import current_region_not_included


Expand All @@ -25,7 +24,7 @@ def test_custom_http_api_domains_regional(self):
self.assertEqual("httpapi.sam-gamma-regional.com", result["DomainName"])

mtls_auth_config = result["MutualTlsAuthentication"]
self.assertEqual(FILE_TO_S3_URI_MAP["MTLSCert.pem"]["uri"], mtls_auth_config["TruststoreUri"])
self.assertEqual(self.file_to_s3_uri_map["MTLSCert.pem"]["uri"], mtls_auth_config["TruststoreUri"])

domain_name_configs = result["DomainNameConfigurations"]
self.assertEqual(1, len(domain_name_configs))
Expand Down
3 changes: 1 addition & 2 deletions integration/combination/test_custom_rest_api_domains.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from integration.config.service_names import CUSTOM_DOMAIN
from integration.helpers.base_internal_test import BaseInternalTest
from integration.helpers.file_resources import FILE_TO_S3_URI_MAP
from integration.helpers.resource import current_region_not_included


Expand Down Expand Up @@ -47,7 +46,7 @@ def test_custom_rest_api_domains_regional(self):
self.assertEqual("REGIONAL", end_point_types[0])

mtls_auth_config = result["mutualTlsAuthentication"]
self.assertEqual(FILE_TO_S3_URI_MAP["MTLSCert.pem"]["uri"], mtls_auth_config["truststoreUri"])
self.assertEqual(self.file_to_s3_uri_map["MTLSCert.pem"]["uri"], mtls_auth_config["truststoreUri"])

def test_custom_rest_api_domains_regional_ownership_verification(self):
self.create_and_verify_stack("combination/api_with_custom_domains_regional_ownership_verification")
Expand Down
4 changes: 4 additions & 0 deletions integration/combination/test_function_with_alias.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import json
from unittest.case import skipIf

from botocore.exceptions import ClientError
from integration.helpers.base_test import BaseTest, LOG
from integration.helpers.common_api import get_function_versions
from integration.helpers.resource import current_region_does_not_support
from integration.config.service_names import REST_API


class TestFunctionWithAlias(BaseTest):
Expand Down Expand Up @@ -82,6 +85,7 @@ def test_alias_in_globals_with_overrides(self):
# add any extra runtime behavior that needs to be verified
self.create_and_verify_stack("combination/function_with_alias_globals")

@skipIf(current_region_does_not_support([REST_API]), "Rest API is not supported in this testing region")
def test_alias_with_event_sources_get_correct_permissions(self):
# There are two parts to testing Event Source integrations:
# 1. Check if all event sources get wired to the alias
Expand Down
5 changes: 5 additions & 0 deletions integration/combination/test_function_with_api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
from unittest.case import skipIf

from integration.helpers.base_test import BaseTest
from integration.helpers.resource import current_region_does_not_support
from integration.config.service_names import REST_API


@skipIf(current_region_does_not_support([REST_API]), "Rest API is not supported in this testing region")
class TestFunctionWithApi(BaseTest):
def test_function_with_api(self):
self.create_and_verify_stack("combination/function_with_api")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from unittest.case import skipIf

from integration.helpers.base_test import BaseTest
from integration.helpers.common_api import get_queue_policy
from integration.helpers.resource import first_item_in_dict, current_region_does_not_support
from integration.config.service_names import CWE_CWS_DLQ

Expand Down Expand Up @@ -30,9 +31,7 @@ def test_function_with_cwe(self):

# checking if the generated dead-letter queue has necessary resource based policy attached to it
sqs_client = self.client_provider.sqs_client
dlq_policy_result = sqs_client.get_queue_attributes(QueueUrl=lambda_target_dlq_url, AttributeNames=["Policy"])
dlq_policy_doc = dlq_policy_result["Attributes"]["Policy"]
dlq_policy = json.loads(dlq_policy_doc)["Statement"]
dlq_policy = get_queue_policy(queue_url=lambda_target_dlq_url, sqs_client=sqs_client)
self.assertEqual(len(dlq_policy), 1, "Only one statement must be in Dead-letter queue policy")
dlq_policy_statement = dlq_policy[0]

Expand Down
19 changes: 18 additions & 1 deletion integration/combination/test_function_with_file_system_config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
from unittest.case import skipIf
import pytest

from integration.config.service_names import EFS
from integration.helpers.base_test import BaseTest
from integration.helpers.resource import current_region_does_not_support


class TestFunctionWithFileSystemConfig(BaseTest):
@pytest.fixture(autouse=True)
def companion_stack_outputs(self, get_companion_stack_outputs):
self.companion_stack_outputs = get_companion_stack_outputs

@skipIf(current_region_does_not_support([EFS]), "EFS is not supported in this testing region")
def test_function_with_efs_integration(self):
self.create_and_verify_stack("combination/function_with_file_system_config")
parameters = self.get_parameters(self.companion_stack_outputs)
self.create_and_verify_stack("combination/function_with_file_system_config", parameters)

def get_parameters(self, dictionary):
parameters = []
parameters.append(self.generate_parameter("PreCreatedSubnetOne", dictionary["PreCreatedSubnetOne"]))
parameters.append(self.generate_parameter("PreCreatedVpc", dictionary["PreCreatedVpc"]))
return parameters
6 changes: 6 additions & 0 deletions integration/combination/test_function_with_http_api.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import logging
from unittest.case import skipIf

import pytest

from integration.helpers.base_test import BaseTest
from integration.helpers.resource import current_region_does_not_support
from integration.config.service_names import HTTP_API

LOG = logging.getLogger(__name__)


@skipIf(current_region_does_not_support([HTTP_API]), "HttpApi is not supported in this testing region")
class TestFunctionWithHttpApi(BaseTest):
@pytest.mark.flaky(reruns=5)
def test_function_with_http_api(self):
self.create_and_verify_stack("combination/function_with_http_api")

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
from unittest.case import skipIf

from integration.helpers.base_test import BaseTest
from integration.helpers.resource import current_region_does_not_support
from integration.config.service_names import REST_API


@skipIf(current_region_does_not_support([REST_API]), "Rest API is not supported in this testing region")
class TestFunctionWithImplicitApiAndCondition(BaseTest):
def test_function_with_implicit_api_and_conditions(self):
self.create_and_verify_stack("combination/function_with_implicit_api_and_conditions")
Loading

0 comments on commit 4c3f5f8

Please sign in to comment.