Skip to content

Commit 8505451

Browse files
Merge release-v1.49.0 into main
2 parents 4c3f5f8 + 1eebf86 commit 8505451

16 files changed

+719
-5
lines changed

integration/combination/test_function_with_s3_bucket.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
from unittest.case import skipIf
2+
13
from integration.helpers.base_test import BaseTest
4+
from integration.helpers.resource import current_region_does_not_support
5+
from integration.config.service_names import S3_EVENTS
26

37

8+
@skipIf(current_region_does_not_support([S3_EVENTS]), "S3 Events feature is not supported in this testing region")
49
class TestFunctionWithS3Bucket(BaseTest):
510
def test_function_with_s3_bucket_trigger(self):
611
self.create_and_verify_stack("combination/function_with_s3")

integration/config/service_names.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@
2323
CUSTOM_DOMAIN = "CustomDomain"
2424
ARM = "ARM"
2525
EFS = "EFS"
26+
S3_EVENTS = "S3Events"

integration/single/test_function_with_http_api_and_auth.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,27 @@
1+
import logging
2+
from unittest.case import skipIf
3+
4+
from tenacity import stop_after_attempt, retry_if_exception_type, after_log, wait_exponential, retry, wait_random
5+
16
from integration.helpers.base_test import BaseTest
7+
from integration.helpers.resource import current_region_does_not_support
8+
9+
LOG = logging.getLogger(__name__)
210

311

12+
@skipIf(current_region_does_not_support(["HttpApi"]), "HttpApi is not supported in this testing region")
413
class TestFunctionWithHttpApiAndAuth(BaseTest):
514
"""
615
AWS::Lambda::Function tests with http api events and auth
716
"""
817

18+
@retry(
19+
stop=stop_after_attempt(5),
20+
wait=wait_exponential(multiplier=1, min=4, max=10) + wait_random(0, 1),
21+
retry=retry_if_exception_type(AssertionError),
22+
after=after_log(LOG, logging.WARNING),
23+
reraise=True,
24+
)
925
def test_function_with_http_api_and_auth(self):
1026
# If the request is not signed, which none of the below are, IAM will respond with a "Forbidden" message.
1127
# We are not testing that IAM auth works here, we are simply testing if it was applied.

samtranslator/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.48.0"
1+
__version__ = "1.49.0"

samtranslator/model/eventsources/push.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class Schedule(PushEventSource):
9696
"Schedule": PropertyType(True, is_str()),
9797
"Input": PropertyType(False, is_str()),
9898
"Enabled": PropertyType(False, is_type(bool)),
99+
"State": PropertyType(False, is_str()),
99100
"Name": PropertyType(False, is_str()),
100101
"Description": PropertyType(False, is_str()),
101102
"DeadLetterConfig": PropertyType(False, is_type(dict)),
@@ -122,8 +123,16 @@ def to_cloudformation(self, **kwargs):
122123
resources.append(events_rule)
123124

124125
events_rule.ScheduleExpression = self.Schedule
126+
127+
if self.State and self.Enabled is not None:
128+
raise InvalidEventException(self.relative_id, "State and Enabled Properties cannot both be specified.")
129+
130+
if self.State:
131+
events_rule.State = self.State
132+
125133
if self.Enabled is not None:
126134
events_rule.State = "ENABLED" if self.Enabled else "DISABLED"
135+
127136
events_rule.Name = self.Name
128137
events_rule.Description = self.Description
129138

samtranslator/swagger/swagger.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,10 @@ def set_path_default_authorizer(
647647
# We want to ensure only a single Authorizer security entry exists while keeping everything else
648648
for security in existing_security:
649649
SwaggerEditor.validate_is_dict(
650-
security, "{} in Security for path {} is not a valid dictionary.".format(security, path)
650+
security,
651+
"{} in Security for path {} method {} is not a valid dictionary.".format(
652+
security, path, method_name
653+
),
651654
)
652655
if authorizer_names.isdisjoint(security.keys()):
653656
existing_non_authorizer_security.append(security)
@@ -703,7 +706,7 @@ def set_path_default_apikey_required(self, path):
703706
:param string path: Path name
704707
"""
705708

706-
for _, method_definition in self.iter_on_all_methods_for_path(path):
709+
for method_name, method_definition in self.iter_on_all_methods_for_path(path):
707710
existing_security = method_definition.get("security", [])
708711
apikey_security_names = set(["api_key", "api_key_false"])
709712
existing_non_apikey_security = []
@@ -714,6 +717,12 @@ def set_path_default_apikey_required(self, path):
714717
# (e.g. sigv4 (AWS_IAM), authorizers, NONE (marker for ignoring default authorizer))
715718
# We want to ensure only a single ApiKey security entry exists while keeping everything else
716719
for security in existing_security:
720+
SwaggerEditor.validate_is_dict(
721+
security,
722+
"{} in Security for path {} method {} is not a valid dictionary.".format(
723+
security, path, method_name
724+
),
725+
)
717726
if apikey_security_names.isdisjoint(security.keys()):
718727
existing_non_apikey_security.append(security)
719728
else:

tests/model/eventsources/test_schedule_event_source.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
from unittest.mock import Mock, patch
21
from unittest import TestCase
32

43
from samtranslator.model.eventsources.push import Schedule
54
from samtranslator.model.lambda_ import LambdaFunction
65
from samtranslator.model.exceptions import InvalidEventException
6+
from parameterized import parameterized
77

88

99
class ScheduleEventSource(TestCase):
@@ -13,6 +13,27 @@ def setUp(self):
1313
self.schedule_event_source.Schedule = "rate(1 minute)"
1414
self.func = LambdaFunction("func")
1515

16+
def test_to_cloudformation_returns_permission_and_schedule_resources(self):
17+
resources = self.schedule_event_source.to_cloudformation(function=self.func)
18+
self.assertEqual(len(resources), 2)
19+
self.assertEqual(resources[0].resource_type, "AWS::Events::Rule")
20+
self.assertEqual(resources[1].resource_type, "AWS::Lambda::Permission")
21+
22+
schedule = resources[0]
23+
self.assertEqual(schedule.ScheduleExpression, "rate(1 minute)")
24+
self.assertIsNone(schedule.State)
25+
26+
def test_to_cloudformation_transforms_enabled_boolean_to_state(self):
27+
self.schedule_event_source.Enabled = True
28+
resources = self.schedule_event_source.to_cloudformation(function=self.func)
29+
schedule = resources[0]
30+
self.assertEqual(schedule.State, "ENABLED")
31+
32+
self.schedule_event_source.Enabled = False
33+
resources = self.schedule_event_source.to_cloudformation(function=self.func)
34+
schedule = resources[0]
35+
self.assertEqual(schedule.State, "DISABLED")
36+
1637
def test_to_cloudformation_with_retry_policy(self):
1738
retry_policy = {"MaximumRetryAttempts": "10", "MaximumEventAgeInSeconds": "300"}
1839
self.schedule_event_source.RetryPolicy = retry_policy
@@ -70,3 +91,19 @@ def test_to_cloudformation_with_dlq_generated_with_intrinsic_function_custom_log
7091
self.schedule_event_source.DeadLetterConfig = dead_letter_config
7192
with self.assertRaises(InvalidEventException):
7293
self.schedule_event_source.to_cloudformation(function=self.func)
94+
95+
@parameterized.expand(
96+
[
97+
(True, "Enabled"),
98+
(True, "Disabled"),
99+
(True, {"FN:FakeIntrinsic": "something"}),
100+
(False, "Enabled"),
101+
(False, "Disabled"),
102+
(False, {"FN:FakeIntrinsic": "something"}),
103+
]
104+
)
105+
def test_to_cloudformation_invalid_defined_both_enabled_and_state_provided(self, enabled_value, state_value):
106+
self.schedule_event_source.Enabled = enabled_value
107+
self.schedule_event_source.State = state_value
108+
with self.assertRaises(InvalidEventException):
109+
self.schedule_event_source.to_cloudformation(function=self.func)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Transform: "AWS::Serverless-2016-10-31"
2+
3+
Resources:
4+
ScheduledFunction:
5+
Type: 'AWS::Serverless::Function'
6+
Properties:
7+
CodeUri: s3://sam-demo-bucket/hello.zip?versionId=3Tcgv52_0GaDvhDva4YciYeqRyPnpIcO
8+
Handler: hello.handler
9+
Runtime: python3.10
10+
Events:
11+
Schedule1:
12+
Type: Schedule
13+
Properties:
14+
Schedule: 'rate(1 minute)'
15+
Name: test-schedule
16+
Description: Test Schedule
17+
State: "Enabled"
18+
Enabled: True
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
transformId: AWS::Serverless-2016-10-31
2+
AWSTemplateFormatVersion: '2010-09-09'
3+
Resources:
4+
AuthFunction:
5+
Type: AWS::Serverless::Function
6+
AccessingPartyAPI:
7+
Type: AWS::Serverless::Api
8+
Properties:
9+
EndpointConfiguration: REGIONAL
10+
StageName: demo
11+
Auth:
12+
ApiKeyRequired: true
13+
14+
DefinitionBody:
15+
paths:
16+
"/path":
17+
put:
18+
responses:
19+
'201':
20+
content:
21+
application/json:
22+
schema:
23+
"$ref": "abcd"
24+
x-amazon-apigateway-integration:
25+
contentHandling: CONVERT_TO_TEXT
26+
responses:
27+
default:
28+
statusCode: '200'
29+
uri:
30+
Fn::Sub: foobar
31+
httpMethod: POST
32+
passthroughBehavior: when_no_match
33+
type: aws_proxy
34+
requestBody:
35+
content:
36+
application/json:
37+
schema:
38+
required:
39+
- readoutId
40+
- status
41+
type: object
42+
security:
43+
- []
44+
45+
openapi: 3.0.3
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
Transform: "AWS::Serverless-2016-10-31"
2+
Parameters:
3+
ScheduleState:
4+
Type: String
5+
Default: Disabled
6+
7+
Resources:
8+
ScheduledFunction:
9+
Type: 'AWS::Serverless::Function'
10+
Properties:
11+
CodeUri: s3://sam-demo-bucket/hello.zip?versionId=3Tcgv52_0GaDvhDva4YciYeqRyPnpIcO
12+
Handler: hello.handler
13+
Runtime: python3.10
14+
Events:
15+
Schedule1:
16+
Type: Schedule
17+
Properties:
18+
Schedule: 'rate(1 minute)'
19+
Name: test-schedule
20+
Description: Test Schedule
21+
State: "Enabled"
22+
Schedule2:
23+
Type: Schedule
24+
Properties:
25+
Schedule: 'rate(1 minute)'
26+
Name: test-schedule
27+
Description: Test Schedule
28+
State: !Sub "Enabled"
29+
Schedule3:
30+
Type: Schedule
31+
Properties:
32+
Schedule: 'rate(1 minute)'
33+
Name: test-schedule
34+
Description: Test Schedule
35+
State: !Ref ScheduleState

0 commit comments

Comments
 (0)