Skip to content

Commit

Permalink
Merge branch 'aws:develop' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
samkenxstream authored Jun 19, 2023
2 parents 5ee00fd + 934f2ef commit 00a0b2f
Show file tree
Hide file tree
Showing 188 changed files with 25,783 additions and 1,167 deletions.
1 change: 1 addition & 0 deletions .cfnlintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ ignore_templates:
- tests/translator/output/**/managed_policies_minimal.json # Intentionally has non-existent managed policy name
- tests/translator/output/**/function_with_mq.json # Property "EventSourceArn" can Fn::GetAtt to a resource of types [AWS::DynamoDB::GlobalTable, AWS::DynamoDB::Table, AWS::Kinesis::Stream, AWS::Kinesis::StreamConsumer, AWS::SQS::Queue]
- tests/translator/output/**/function_with_mq_using_autogen_role.json # Property "EventSourceArn" can Fn::GetAtt to a resource of types [AWS::DynamoDB::GlobalTable, AWS::DynamoDB::Table, AWS::Kinesis::Stream, AWS::Kinesis::StreamConsumer, AWS::SQS::Queue]
- tests/translator/output/**/api_with_propagate_tags.json # Obsolete DependsOn on resource
ignore_checks:
- E2531 # Deprecated runtime; not relevant for transform tests
- W2531 # EOL runtime; not relevant for transform tests
Expand Down
23 changes: 6 additions & 17 deletions DEVELOPMENT_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,27 +134,16 @@ one python version locally and then have our ci (appveyor) run all supported ver

Transform tests ensure a SAM template transforms into the expected CloudFormation template.

When adding new transform tests, we have provided a script to help generate the transform test input
and output files in the correct directory given a `template.yaml` file.
```bash
python3 bin/add_transform_test.py --template-file template.yaml
```

This script will automatically generate the input and output files. It will guarantee that the output
files have the correct AWS partition (e.g. aws-cn, aws-us-gov).
We provide a script to help generate the transform test input
and output files in the correct directory given a SAM template. For example:

For `AWS::ApiGateway::RestApi`, the script will automatically append `REGIONAL` `EndpointConfiguration`.
To disable this feature, run the following command instead.
```bash
python3 bin/add_transform_test.py --template-file template.yaml --disable-api-configuration
```

The script automatically updates hardcoded ARN partitions to match the output partition. To disable this, use:
```bash
python3 bin/add_transform_test.py --template-file template.yaml --disable-update-partition
python3 bin/add_transform_test.py --template-file template.yaml
```

Please always check the generated output is as expected. This tool does not guarantee correct output.
> **Warning**
>
> Always check the generated output is as expected. This tool does not guarantee correct output.
#### Transform failures

Expand Down
52 changes: 8 additions & 44 deletions bin/add_transform_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
from copy import deepcopy
from pathlib import Path
from typing import Any, Dict
from unittest.mock import patch

import boto3

from samtranslator.translator.arn_generator import ArnGenerator
from samtranslator.translator.managed_policy_translator import ManagedPolicyLoader
from samtranslator.translator.transform import transform
from samtranslator.yaml_helper import yaml_parse
Expand All @@ -28,16 +28,6 @@
type=Path,
default=Path("template.yaml"),
)
parser.add_argument(
"--disable-api-configuration",
help="Disable adding REGIONAL configuration to AWS::ApiGateway::RestApi",
action="store_true",
)
parser.add_argument(
"--disable-update-partition",
help="Disable updating the partition of arn to aws-cn/aws-us-gov",
action="store_true",
)
CLI_OPTIONS = parser.parse_args()


Expand All @@ -51,25 +41,6 @@ def write_json_file(obj: Dict[str, Any], file_path: Path) -> None:
json.dump(obj, f, indent=2, sort_keys=True)


def add_regional_endpoint_configuration_if_needed(template: Dict[str, Any]) -> Dict[str, Any]:
for _, resource in template["Resources"].items():
if resource["Type"] == "AWS::ApiGateway::RestApi":
properties = resource["Properties"]
if "EndpointConfiguration" not in properties:
properties["EndpointConfiguration"] = {"Types": ["REGIONAL"]}
if "Parameters" not in properties:
properties["Parameters"] = {"endpointConfigurationTypes": "REGIONAL"}

return template


def replace_aws_partition(partition: str, file_path: Path) -> None:
template = read_json_file(file_path)
updated_template = json.loads(json.dumps(template).replace("arn:aws:", f"arn:{partition}:"))
file_path.write_text(json.dumps(updated_template, indent=2), encoding="utf-8")
print(f"Transform Test output files generated {file_path}")


def generate_transform_test_output_files(input_file_path: Path, file_basename: str) -> None:
output_file_option = file_basename + ".json"

Expand All @@ -82,20 +53,13 @@ def generate_transform_test_output_files(input_file_path: Path, file_basename: s
"aws-us-gov": ("us-gov-west-1", TRANSFORM_TEST_DIR / "output" / "aws-us-gov" / output_file_option),
}

for partition, (region, output_path) in transform_test_output_paths.items():
# Set Boto Session Region to guarantee the same hash input as transform tests for API deployment id
ArnGenerator.BOTO_SESSION_REGION_NAME = region
# Implicit API Plugin may alter input template file, thus passing a copy here.
output_fragment = transform(deepcopy(manifest), {}, ManagedPolicyLoader(iam_client))

if not CLI_OPTIONS.disable_api_configuration and partition != "aws":
output_fragment = add_regional_endpoint_configuration_if_needed(output_fragment)

write_json_file(output_fragment, output_path)

# Update arn partition if necessary
if not CLI_OPTIONS.disable_update_partition:
replace_aws_partition(partition, output_path)
for _, (region, output_path) in transform_test_output_paths.items():
with patch("samtranslator.translator.arn_generator._get_region_from_session", return_value=region), patch(
"boto3.session.Session.region_name", region
):
# Implicit API Plugin may alter input template file, thus passing a copy here.
output_fragment = transform(deepcopy(manifest), {}, ManagedPolicyLoader(iam_client))
write_json_file(output_fragment, output_path)


def get_input_file_path() -> Path:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from unittest.case import skipIf

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


@skipIf(
current_region_does_not_support([HTTP_API, REST_API]),
"REST_API or HTTP_API is not supported in this testing region",
)
class TestApiAndHttpiWithPropagateTags(BaseTest):
def test_api_and_httpapi_with_propagate_tags(self):
self.create_and_verify_stack("combination/api_with_propagate_tags")

outputs = self.get_stack_outputs()

api_client = self.client_provider.api_client
api_v2_client = self.client_provider.api_v2_client

tags = api_client.get_tags(resourceArn=outputs["ApiArn"])
self.assertEqual(tags["tags"]["Key1"], "Value1")
self.assertEqual(tags["tags"]["Key2"], "Value2")

tags = api_v2_client.get_tags(ResourceArn=outputs["HttpApiArn"])
self.assertEqual(tags["Tags"]["Tag1"], "value1")
self.assertEqual(tags["Tags"]["Tag2"], "value2")
101 changes: 101 additions & 0 deletions integration/combination/test_graphqlapi_lambda_resolver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import json
from unittest.case import skipIf

import requests

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


def execute_and_verify_appsync_query(url, api_key, query):
"""
Executes a query to an AppSync GraphQLApi.
Also checks that the response is 200 and does not contain errors before returning.
"""
headers = {
"Content-Type": "application/json",
"x-api-key": api_key,
}
payload = {"query": query}

response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
data = response.json()
if "errors" in data:
raise Exception(json.dumps(data["errors"]))

return data


@skipIf(current_region_does_not_support([APP_SYNC]), "AppSync is not supported in this testing region")
class TestGraphQLApiPipelineResolver(BaseTest):
def test_api(self):
file_name = "combination/graphqlapi_lambda_resolver"
self.create_and_verify_stack(file_name)

outputs = self.get_stack_outputs()

author = "AUTHORNAME"
title = "Our first post!"
content = "This is our first post."

query = f"""
mutation addPost {{
addPost(
id: 100
author: "{author}"
title: "{title}"
content: "{content}"
) {{
id
author
title
content
}}
}}
"""

url = outputs["SuperCoolAPI"]
api_key = outputs["SuperCoolAPIMyApiKey"]

response = execute_and_verify_appsync_query(url, api_key, query)

add_post = response["data"]["addPost"]

self.assertEqual(add_post["id"], "100")
self.assertEqual(add_post["author"], author)
self.assertEqual(add_post["title"], title)
self.assertEqual(add_post["content"], content)

query = """
query getPost {
getPost(id:"1") {
id
author
title
content
ups
downs
}
}
"""

response = execute_and_verify_appsync_query(url, api_key, query)

get_post = response["data"]["getPost"]

# These values are hardcoded inside the Lambda function for a post with id "1".
author = "Author1"
title = "First book"
content = "Book 1 has this content"
ups = 100
downs = 10

self.assertEqual(get_post["id"], "1")
self.assertEqual(get_post["author"], author)
self.assertEqual(get_post["title"], title)
self.assertEqual(get_post["content"], content)
self.assertEqual(get_post["ups"], ups)
self.assertEqual(get_post["downs"], downs)
101 changes: 101 additions & 0 deletions integration/combination/test_graphqlapi_pipeline_resolver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import json
from unittest.case import skipIf

import requests

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


def execute_and_verify_appsync_query(url, api_key, query):
"""
Executes a query to an AppSync GraphQLApi.
Also checks that the response is 200 and does not contain errors before returning.
"""
headers = {
"Content-Type": "application/json",
"x-api-key": api_key,
}
payload = {"query": query}

response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
data = response.json()
if "errors" in data:
raise Exception(json.dumps(data["errors"]))

return data


@skipIf(current_region_does_not_support([APP_SYNC]), "AppSync is not supported in this testing region")
class TestGraphQLApiPipelineResolver(BaseTest):
def test_api(self):
file_name = "combination/graphqlapi_pipeline_resolver"
self.create_and_verify_stack(file_name)

outputs = self.get_stack_outputs()

author = "AUTHORNAME"
title = "Our first post!"
content = "This is our first post."

query = f"""
mutation addPost {{
addPost(
author: "{author}"
title: "{title}"
content: "{content}"
) {{
id
author
title
content
ups
downs
version
}}
}}
"""

url = outputs["SuperCoolAPI"]
api_key = outputs["MyApiKey"]

response = execute_and_verify_appsync_query(url, api_key, query)

add_post = response["data"]["addPost"]

self.assertEqual(add_post["author"], author)
self.assertEqual(add_post["title"], title)
self.assertEqual(add_post["content"], content)
self.assertEqual(add_post["ups"], 1)
self.assertEqual(add_post["downs"], 0)
self.assertEqual(add_post["version"], 1)

post_id = add_post["id"]
query = f"""
query getPost {{
getPost(id:"{post_id}") {{
id
author
title
content
ups
downs
version
}}
}}
"""

response = execute_and_verify_appsync_query(url, api_key, query)

get_post = response["data"]["getPost"]

self.assertEqual(get_post["author"], author)
self.assertEqual(get_post["title"], title)
self.assertEqual(get_post["content"], content)
self.assertEqual(get_post["ups"], 1)
self.assertEqual(get_post["downs"], 0)
self.assertEqual(get_post["version"], 1)
self.assertEqual(get_post["id"], post_id)
3 changes: 2 additions & 1 deletion integration/combination/test_state_machine_with_schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from parameterized import parameterized

from integration.config.service_names import STATE_MACHINE_CWE_CWS
from integration.helpers.base_test import BaseTest
from integration.helpers.base_test import BaseTest, nonblocking
from integration.helpers.common_api import get_policy_statements
from integration.helpers.resource import current_region_does_not_support

Expand All @@ -12,6 +12,7 @@
current_region_does_not_support([STATE_MACHINE_CWE_CWS]),
"StateMachine CweCws is not supported in this testing region",
)
@nonblocking
class TestStateMachineWithSchedule(BaseTest):
@parameterized.expand(
[
Expand Down
1 change: 0 additions & 1 deletion integration/config/service_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
LAMBDA_URL = "LambdaUrl"
LAMBDA_ENV_VARS = "LambdaEnvVars"
EVENT_INVOKE_CONFIG = "EventInvokeConfig"
EPHEMERAL_STORAGE = "EphemeralStorage"
API_KEY = "ApiKey"
APP_SYNC = "AppSync"
SNS_FILTER_POLICY_SCOPE = "SnsFilterPolicyScope"
Loading

0 comments on commit 00a0b2f

Please sign in to comment.