Skip to content

Commit 063ac27

Browse files
authored
Merge pull request #3211 from aws/release-v1.69.0
Release 1.69.0 (to main)
2 parents 12a7b02 + a4fc228 commit 063ac27

File tree

161 files changed

+29931
-3109
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

161 files changed

+29931
-3109
lines changed

.cfnlintrc.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ ignore_templates:
122122
- tests/translator/output/**/function_with_runtime_config.json # RuntimeManagementConfig
123123
- tests/translator/output/**/managed_policies_minimal.json # Intentionally has non-existent managed policy name
124124
- 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]
125+
- 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]
125126
ignore_checks:
126127
- E2531 # Deprecated runtime; not relevant for transform tests
127128
- W2531 # EOL runtime; not relevant for transform tests

.github/workflows/schema.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Update schema
33
on:
44
workflow_dispatch:
55
schedule:
6-
- cron: "0 0 * * 1-5" # Weekdays
6+
- cron: "0 18 * * 1-5" # Weekdays
77

88
jobs:
99
update:

DEVELOPMENT_GUIDE.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,18 +130,20 @@ one python version locally and then have our ci (appveyor) run all supported ver
130130

131131
### Transform tests
132132

133+
#### Successful transforms
134+
133135
Transform tests ensure a SAM template transforms into the expected CloudFormation template.
134136

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

141143
This script will automatically generate the input and output files. It will guarantee that the output
142144
files have the correct AWS partition (e.g. aws-cn, aws-us-gov).
143145

144-
For `AWS::ApiGateway::RestApi`, the script will automatically append `REGIONAL` EndpointConfiguration.
146+
For `AWS::ApiGateway::RestApi`, the script will automatically append `REGIONAL` `EndpointConfiguration`.
145147
To disable this feature, run the following command instead.
146148
```bash
147149
python3 bin/add_transform_test.py --template-file template.yaml --disable-api-configuration
@@ -152,8 +154,13 @@ The script automatically updates hardcoded ARN partitions to match the output pa
152154
python3 bin/add_transform_test.py --template-file template.yaml --disable-update-partition
153155
```
154156

155-
Note that please always check the generated output is as expected. This tool does not guarantee correct output.
157+
Please always check the generated output is as expected. This tool does not guarantee correct output.
158+
159+
#### Transform failures
160+
161+
To test a SAM template results in a specific transform error, add the SAM template under [`tests/translator/input`](https://github.com/aws/serverless-application-model/tree/develop/tests/translator/input), and a JSON file with the expected `errorMessage` as a top-level value under [`tests/translator/output`](https://github.com/aws/serverless-application-model/tree/develop/tests/translator/output). Both files must have the same basename and be prefixed with `error_` (e.g. `error_my_cool_template.yaml` for input, and `error_my_cool_template.json` for the expected error).
156162

163+
See https://github.com/aws/serverless-application-model/pull/2993 for an example.
157164

158165
### Integration tests
159166

@@ -205,7 +212,7 @@ The AWS SAM specification includes a JSON schema (see https://github.com/aws/ser
205212

206213
To add new properties, do the following:
207214

208-
1. Add the property to the relevant resource schema under [`samtranslator/schema`](https://github.com/aws/serverless-application-model/tree/develop/samtranslator/schema) (e.g. [`samtranslator/schema/aws_serverless_function.py`](https://github.com/aws/serverless-application-model/blob/develop/samtranslator/schema/aws_serverless_function.py) for `AWS::Serverless::Function`).
215+
1. Add the property to the relevant resource schema under [`samtranslator/internal/schema_source`](https://github.com/aws/serverless-application-model/tree/develop/samtranslator/internal/schema_source) (e.g. [`samtranslator/internal/schema_source/aws_serverless_function.py`](https://github.com/aws/serverless-application-model/blob/develop/samtranslator/internal/schema_source/aws_serverless_function.py) for `AWS::Serverless::Function`).
209216
2. You can leave out the assignement part; it adds documentation to the schema properties. The team will take care of documentation updates once code changes are merged. Typically we update documentation by running `make update-schema-data`.
210217
3. Run `make schema`.
211218

integration/combination/test_custom_http_api_domains_test.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
from integration.config.service_names import CUSTOM_DOMAIN
44
from integration.helpers.base_internal_test import BaseInternalTest
5+
from integration.helpers.base_test import nonblocking
56
from integration.helpers.resource import current_region_not_included
67

78

89
@skipIf(
910
current_region_not_included([CUSTOM_DOMAIN]),
1011
"CustomDomain is not supported in this testing region",
1112
)
13+
@nonblocking
1214
class TestCustomHttpApiDomains(BaseInternalTest):
1315
def test_custom_http_api_domains_regional(self):
1416
self.create_and_verify_stack("combination/http_api_with_custom_domains_regional")

integration/combination/test_custom_rest_api_domains.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
from integration.config.service_names import CUSTOM_DOMAIN
44
from integration.helpers.base_internal_test import BaseInternalTest
5+
from integration.helpers.base_test import nonblocking
56
from integration.helpers.resource import current_region_not_included
67

78

89
@skipIf(
910
current_region_not_included([CUSTOM_DOMAIN]),
1011
"CustomDomain is not supported in this testing region",
1112
)
13+
@nonblocking
1214
class TestCustomRestApiDomains(BaseInternalTest):
1315
def test_custom_rest_api_domains_edge(self):
1416
self.create_and_verify_stack("combination/api_with_custom_domains_edge")

integration/combination/test_function_with_mq.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from parameterized import parameterized
55

66
from integration.config.service_names import MQ
7-
from integration.helpers.base_test import BaseTest
7+
from integration.helpers.base_test import BaseTest, nonblocking
88
from integration.helpers.resource import current_region_does_not_support, generate_suffix
99

1010

@@ -25,11 +25,8 @@ def companion_stack_outputs(self, get_companion_stack_outputs):
2525
),
2626
]
2727
)
28+
@nonblocking
2829
def test_function_with_mq(self, file_name, mq_broker, mq_secret, subnet_key):
29-
# Temporarily skip this test and we should either re-enable this once the AZ issue is fixed
30-
# or once we figure out a way to trigger integ test only when transform output changes.
31-
if subnet_key == "PreCreatedSubnetOne":
32-
pytest.skip("Skipping this test to temporarily bypass AvailabilityZone issue.")
3330
companion_stack_outputs = self.companion_stack_outputs
3431
parameters = self.get_parameters(companion_stack_outputs, subnet_key)
3532
secret_name = mq_secret + "-" + generate_suffix()

integration/combination/test_function_with_msk.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
import pytest
44

55
from integration.config.service_names import MSK
6-
from integration.helpers.base_test import BaseTest
6+
from integration.helpers.base_test import BaseTest, nonblocking
77
from integration.helpers.resource import current_region_does_not_support, generate_suffix
88

99

1010
@skipIf(current_region_does_not_support([MSK]), "MSK is not supported in this testing region")
11+
@nonblocking
1112
class TestFunctionWithMsk(BaseTest):
1213
@pytest.fixture(autouse=True)
1314
def companion_stack_outputs(self, get_companion_stack_outputs):
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import json
2+
from unittest.case import skipIf
3+
4+
import requests
5+
6+
from integration.config.service_names import APP_SYNC
7+
from integration.helpers.base_test import BaseTest
8+
from integration.helpers.resource import current_region_does_not_support
9+
10+
11+
def execute_and_verify_appsync_query(url, api_key, query):
12+
"""
13+
Executes a query to an AppSync GraphQLApi.
14+
15+
Also checks that the response is 200 and does not contain errors before returning.
16+
"""
17+
headers = {
18+
"Content-Type": "application/json",
19+
"x-api-key": api_key,
20+
}
21+
payload = {"query": query}
22+
23+
response = requests.post(url, json=payload, headers=headers)
24+
response.raise_for_status()
25+
data = response.json()
26+
if "errors" in data:
27+
raise Exception(json.dumps(data["errors"]))
28+
29+
return data
30+
31+
32+
@skipIf(current_region_does_not_support([APP_SYNC]), "AppSync is not supported in this testing region")
33+
class TestGraphQLApiPipelineResolver(BaseTest):
34+
def test_api(self):
35+
file_name = "combination/graphqlapi_lambda_resolver"
36+
self.create_and_verify_stack(file_name)
37+
38+
outputs = self.get_stack_outputs()
39+
40+
author = "AUTHORNAME"
41+
title = "Our first post!"
42+
content = "This is our first post."
43+
44+
query = f"""
45+
mutation addPost {{
46+
addPost(
47+
id: 100
48+
author: "{author}"
49+
title: "{title}"
50+
content: "{content}"
51+
) {{
52+
id
53+
author
54+
title
55+
content
56+
}}
57+
}}
58+
"""
59+
60+
url = outputs["SuperCoolAPI"]
61+
api_key = outputs["SuperCoolAPIMyApiKey"]
62+
63+
response = execute_and_verify_appsync_query(url, api_key, query)
64+
65+
add_post = response["data"]["addPost"]
66+
67+
self.assertEqual(add_post["id"], "100")
68+
self.assertEqual(add_post["author"], author)
69+
self.assertEqual(add_post["title"], title)
70+
self.assertEqual(add_post["content"], content)
71+
72+
query = """
73+
query getPost {
74+
getPost(id:"1") {
75+
id
76+
author
77+
title
78+
content
79+
ups
80+
downs
81+
}
82+
}
83+
"""
84+
85+
response = execute_and_verify_appsync_query(url, api_key, query)
86+
87+
get_post = response["data"]["getPost"]
88+
89+
# These values are hardcoded inside the Lambda function for a post with id "1".
90+
author = "Author1"
91+
title = "First book"
92+
content = "Book 1 has this content"
93+
ups = 100
94+
downs = 10
95+
96+
self.assertEqual(get_post["id"], "1")
97+
self.assertEqual(get_post["author"], author)
98+
self.assertEqual(get_post["title"], title)
99+
self.assertEqual(get_post["content"], content)
100+
self.assertEqual(get_post["ups"], ups)
101+
self.assertEqual(get_post["downs"], downs)
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import json
2+
from unittest.case import skipIf
3+
4+
import requests
5+
6+
from integration.config.service_names import APP_SYNC
7+
from integration.helpers.base_test import BaseTest
8+
from integration.helpers.resource import current_region_does_not_support
9+
10+
11+
def execute_and_verify_appsync_query(url, api_key, query):
12+
"""
13+
Executes a query to an AppSync GraphQLApi.
14+
15+
Also checks that the response is 200 and does not contain errors before returning.
16+
"""
17+
headers = {
18+
"Content-Type": "application/json",
19+
"x-api-key": api_key,
20+
}
21+
payload = {"query": query}
22+
23+
response = requests.post(url, json=payload, headers=headers)
24+
response.raise_for_status()
25+
data = response.json()
26+
if "errors" in data:
27+
raise Exception(json.dumps(data["errors"]))
28+
29+
return data
30+
31+
32+
@skipIf(current_region_does_not_support([APP_SYNC]), "AppSync is not supported in this testing region")
33+
class TestGraphQLApiPipelineResolver(BaseTest):
34+
def test_api(self):
35+
file_name = "combination/graphqlapi_pipeline_resolver"
36+
self.create_and_verify_stack(file_name)
37+
38+
outputs = self.get_stack_outputs()
39+
40+
author = "AUTHORNAME"
41+
title = "Our first post!"
42+
content = "This is our first post."
43+
44+
query = f"""
45+
mutation addPost {{
46+
addPost(
47+
author: "{author}"
48+
title: "{title}"
49+
content: "{content}"
50+
) {{
51+
id
52+
author
53+
title
54+
content
55+
ups
56+
downs
57+
version
58+
}}
59+
}}
60+
"""
61+
62+
url = outputs["SuperCoolAPI"]
63+
api_key = outputs["MyApiKey"]
64+
65+
response = execute_and_verify_appsync_query(url, api_key, query)
66+
67+
add_post = response["data"]["addPost"]
68+
69+
self.assertEqual(add_post["author"], author)
70+
self.assertEqual(add_post["title"], title)
71+
self.assertEqual(add_post["content"], content)
72+
self.assertEqual(add_post["ups"], 1)
73+
self.assertEqual(add_post["downs"], 0)
74+
self.assertEqual(add_post["version"], 1)
75+
76+
post_id = add_post["id"]
77+
query = f"""
78+
query getPost {{
79+
getPost(id:"{post_id}") {{
80+
id
81+
author
82+
title
83+
content
84+
ups
85+
downs
86+
version
87+
}}
88+
}}
89+
"""
90+
91+
response = execute_and_verify_appsync_query(url, api_key, query)
92+
93+
get_post = response["data"]["getPost"]
94+
95+
self.assertEqual(get_post["author"], author)
96+
self.assertEqual(get_post["title"], title)
97+
self.assertEqual(get_post["content"], content)
98+
self.assertEqual(get_post["ups"], 1)
99+
self.assertEqual(get_post["downs"], 0)
100+
self.assertEqual(get_post["version"], 1)
101+
self.assertEqual(get_post["id"], post_id)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
[
2+
{
3+
"LogicalResourceId": "MyLambdaFunction",
4+
"ResourceType": "AWS::Lambda::Function"
5+
},
6+
{
7+
"LogicalResourceId": "LambdaFunctionRole",
8+
"ResourceType": "AWS::IAM::Role"
9+
},
10+
{
11+
"LogicalResourceId": "SuperCoolAPI",
12+
"ResourceType": "AWS::AppSync::GraphQLApi"
13+
},
14+
{
15+
"LogicalResourceId": "SuperCoolAPISchema",
16+
"ResourceType": "AWS::AppSync::GraphQLSchema"
17+
},
18+
{
19+
"LogicalResourceId": "SuperCoolAPICloudWatchRole",
20+
"ResourceType": "AWS::IAM::Role"
21+
},
22+
{
23+
"LogicalResourceId": "SuperCoolAPIMyApiKey",
24+
"ResourceType": "AWS::AppSync::ApiKey"
25+
},
26+
{
27+
"LogicalResourceId": "SuperCoolAPIMyLambdaDataSourceLambdaDataSource",
28+
"ResourceType": "AWS::AppSync::DataSource"
29+
},
30+
{
31+
"LogicalResourceId": "SuperCoolAPIMyLambdaDataSourceLambdaDataSourceRole",
32+
"ResourceType": "AWS::IAM::Role"
33+
},
34+
{
35+
"LogicalResourceId": "SuperCoolAPIMyLambdaDataSourceLambdaDataSourceToLambdaConnectorPolicy",
36+
"ResourceType": "AWS::IAM::ManagedPolicy"
37+
},
38+
{
39+
"LogicalResourceId": "SuperCoolAPIlambdaInvoker",
40+
"ResourceType": "AWS::AppSync::FunctionConfiguration"
41+
},
42+
{
43+
"LogicalResourceId": "SuperCoolAPIMutationaddPost",
44+
"ResourceType": "AWS::AppSync::Resolver"
45+
},
46+
{
47+
"LogicalResourceId": "SuperCoolAPIQuerygetPost",
48+
"ResourceType": "AWS::AppSync::Resolver"
49+
}
50+
]

0 commit comments

Comments
 (0)