From 14bcadc300f5ef89400c224b734c6e54a8eb48c8 Mon Sep 17 00:00:00 2001 From: "localstack[bot]" Date: Sat, 23 Nov 2024 21:35:58 +0000 Subject: [PATCH 01/38] prepare next development iteration From 43187f7054dfcdd9e0729408b07cffbb9fe82008 Mon Sep 17 00:00:00 2001 From: LocalStack Bot <88328844+localstack-bot@users.noreply.github.com> Date: Mon, 25 Nov 2024 09:32:17 +0100 Subject: [PATCH 02/38] Update CODEOWNERS (#11919) Co-authored-by: LocalStack Bot --- CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/CODEOWNERS b/CODEOWNERS index 4442770660039..8d387cedb677b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -236,6 +236,7 @@ /localstack-core/localstack/aws/api/stepfunctions/ @MEPalma @joe4dev @dominikschubert @gregfurman /localstack-core/localstack/services/stepfunctions/ @MEPalma @joe4dev @dominikschubert @gregfurman /tests/aws/services/stepfunctions/ @MEPalma @joe4dev @dominikschubert @gregfurman +/tests/unit/services/stepfunctions/ @MEPalma @joe4dev @dominikschubert @gregfurman # sts /localstack-core/localstack/aws/api/sts/ @pinzon @dfangl From 4803c4cb0d24191047bb48333651c6fa260dad05 Mon Sep 17 00:00:00 2001 From: Anisa Oshafi Date: Mon, 25 Nov 2024 12:05:47 +0100 Subject: [PATCH 03/38] Lambda: Fix behaviour for alias update and delete operations (#11878) --- .../localstack/services/lambda_/provider.py | 9 +- tests/aws/services/lambda_/test_lambda_api.py | 136 +++++++++++ .../lambda_/test_lambda_api.snapshot.json | 215 +++++++++++++++++- .../lambda_/test_lambda_api.validation.json | 21 +- 4 files changed, 365 insertions(+), 16 deletions(-) diff --git a/localstack-core/localstack/services/lambda_/provider.py b/localstack-core/localstack/services/lambda_/provider.py index a6975a3ad0c95..9abf3cebac384 100644 --- a/localstack-core/localstack/services/lambda_/provider.py +++ b/localstack-core/localstack/services/lambda_/provider.py @@ -1770,8 +1770,6 @@ def delete_alias( function = self._get_function( function_name=function_name, region=region, account_id=account_id ) - if name not in function.aliases: - raise ValueError("Alias not found") # TODO proper exception version_alias = function.aliases.pop(name, None) # cleanup related resources @@ -1819,7 +1817,11 @@ def update_alias( function_name=function_name, region=region, account_id=account_id ) if not (alias := function.aliases.get(name)): - raise ValueError("Alias not found") # TODO proper exception + fn_arn = api_utils.qualified_lambda_arn(function_name, name, account_id, region) + raise ResourceNotFoundException( + f"Alias not found: {fn_arn}", + Type="User", + ) if revision_id and alias.revision_id != revision_id: raise PreconditionFailedException( "The Revision Id provided does not match the latest Revision Id. " @@ -2363,7 +2365,6 @@ def update_function_url_config( InvokeMode=new_url_config.invoke_mode, ) - # TODO: does only specifying the function name, also delete the ones from all related aliases? def delete_function_url_config( self, context: RequestContext, diff --git a/tests/aws/services/lambda_/test_lambda_api.py b/tests/aws/services/lambda_/test_lambda_api.py index 8bbe5c39c57bf..bd69fd5e591f0 100644 --- a/tests/aws/services/lambda_/test_lambda_api.py +++ b/tests/aws/services/lambda_/test_lambda_api.py @@ -2136,6 +2136,66 @@ def test_alias_lifecycle( ) # 3 aliases snapshot.match("list_aliases_for_fnname_afterdelete", list_aliases_for_fnname_afterdelete) + @markers.aws.validated + def test_non_existent_alias_deletion( + self, create_lambda_function_aws, lambda_su_role, snapshot, aws_client + ): + """ + This test checks the behaviour when deleting a non-existent alias. + No error is raised. + """ + function_name = f"alias-fn-{short_uid()}" + create_response = create_lambda_function_aws( + FunctionName=function_name, + Handler="index.handler", + Code={ + "ZipFile": create_lambda_archive( + load_file(TEST_LAMBDA_PYTHON_ECHO), get_content=True + ) + }, + PackageType="Zip", + Role=lambda_su_role, + Runtime=Runtime.python3_12, + Environment={"Variables": {"testenv": "staging"}}, + ) + snapshot.match("create_response", create_response) + + delete_alias_response = aws_client.lambda_.delete_alias( + FunctionName=function_name, Name="non-existent" + ) + snapshot.match("delete_alias_response", delete_alias_response) + + @markers.aws.validated + def test_non_existent_alias_update( + self, create_lambda_function_aws, lambda_su_role, snapshot, aws_client + ): + """ + This test checks the behaviour when updating a non-existent alias. + An error (ResourceNotFoundException) is raised. + """ + function_name = f"alias-fn-{short_uid()}" + create_response = create_lambda_function_aws( + FunctionName=function_name, + Handler="index.handler", + Code={ + "ZipFile": create_lambda_archive( + load_file(TEST_LAMBDA_PYTHON_ECHO), get_content=True + ) + }, + PackageType="Zip", + Role=lambda_su_role, + Runtime=Runtime.python3_12, + Environment={"Variables": {"testenv": "staging"}}, + ) + snapshot.match("create_response", create_response) + + with pytest.raises(aws_client.lambda_.exceptions.ResourceNotFoundException) as e: + aws_client.lambda_.update_alias( + FunctionName=function_name, + Name="non-existent", + ) + snapshot.match("update_alias_response", e.value.response) + @markers.aws.validated def test_notfound_and_invalid_routingconfigs( self, aws_client_factory, create_lambda_function_aws, snapshot, lambda_su_role, aws_client @@ -4468,6 +4528,82 @@ def test_url_config_lifecycle(self, create_lambda_function, snapshot, aws_client aws_client.lambda_.get_function_url_config(FunctionName=function_name) snapshot.match("failed_getter", ex.value.response) + @markers.snapshot.skip_snapshot_verify(paths=["$..InvokeMode"]) + @markers.aws.validated + def test_url_config_deletion_without_qualifier( + self, create_lambda_function_aws, lambda_su_role, snapshot, aws_client + ): + """ + This test checks that delete_function_url_config doesn't delete the function url configs of all aliases, + when not specifying the Qualifier. + """ + snapshot.add_transformer( + snapshot.transform.key_value("FunctionUrl", "lambda-url", reference_replacement=False) + ) + + function_name = f"alias-fn-{short_uid()}" + create_lambda_function_aws( + FunctionName=function_name, + Handler="index.handler", + Code={ + "ZipFile": create_lambda_archive( + load_file(TEST_LAMBDA_PYTHON_ECHO), get_content=True + ) + }, + PackageType="Zip", + Role=lambda_su_role, + Runtime=Runtime.python3_12, + Environment={"Variables": {"testenv": "staging"}}, + ) + aws_client.lambda_.publish_version(FunctionName=function_name) + + alias_name = "test-alias" + aws_client.lambda_.create_alias( + FunctionName=function_name, + Name=alias_name, + FunctionVersion="1", + Description="custom-alias", + ) + + url_config_created = aws_client.lambda_.create_function_url_config( + FunctionName=function_name, + AuthType="NONE", + ) + snapshot.match("url_creation", url_config_created) + + url_config_with_alias_created = aws_client.lambda_.create_function_url_config( + FunctionName=function_name, + AuthType="NONE", + Qualifier=alias_name, + ) + snapshot.match("url_with_alias_creation", url_config_with_alias_created) + + url_config_obtained = aws_client.lambda_.get_function_url_config(FunctionName=function_name) + snapshot.match("get_url_config", url_config_obtained) + + url_config_obtained_with_alias = aws_client.lambda_.get_function_url_config( + FunctionName=function_name, Qualifier=alias_name + ) + snapshot.match("get_url_config_with_alias", url_config_obtained_with_alias) + + # delete function url config by only specifying function name (no qualifier) + delete_function_url_config_response = aws_client.lambda_.delete_function_url_config( + FunctionName=function_name + ) + snapshot.match("delete_function_url_config", delete_function_url_config_response) + + with pytest.raises(aws_client.lambda_.exceptions.ResourceNotFoundException) as e: + aws_client.lambda_.get_function_url_config(FunctionName=function_name) + snapshot.match("get_url_config_after_deletion", e.value.response) + + # only specifying the function name, doesn't delete the url config from all related aliases + get_url_config_with_alias_after_deletion = aws_client.lambda_.get_function_url_config( + FunctionName=function_name, Qualifier=alias_name + ) + snapshot.match( + "get_url_config_with_alias_after_deletion", get_url_config_with_alias_after_deletion + ) + @markers.aws.only_localstack def test_create_url_config_custom_id_tag(self, create_lambda_function, aws_client): custom_id_value = "my-custom-subdomain" diff --git a/tests/aws/services/lambda_/test_lambda_api.snapshot.json b/tests/aws/services/lambda_/test_lambda_api.snapshot.json index 53e078fb0e431..b60e0d4965f66 100644 --- a/tests/aws/services/lambda_/test_lambda_api.snapshot.json +++ b/tests/aws/services/lambda_/test_lambda_api.snapshot.json @@ -3029,7 +3029,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_alias_lifecycle": { - "recorded-date": "10-04-2024, 09:12:28", + "recorded-date": "21-11-2024, 13:44:49", "recorded-content": { "create_response": { "Architectures": [ @@ -3621,7 +3621,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_notfound_and_invalid_routingconfigs": { - "recorded-date": "10-04-2024, 09:12:41", + "recorded-date": "21-11-2024, 13:45:06", "recorded-content": { "create_response": { "Architectures": [ @@ -5257,7 +5257,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_lifecycle": { - "recorded-date": "10-04-2024, 09:17:00", + "recorded-date": "21-11-2024, 13:44:13", "recorded-content": { "url_creation": { "AuthType": "NONE", @@ -7076,7 +7076,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_list_paging": { - "recorded-date": "10-04-2024, 09:16:55", + "recorded-date": "21-11-2024, 13:44:10", "recorded-content": { "fn_version_result": { "Architectures": [ @@ -7200,7 +7200,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_exceptions": { - "recorded-date": "10-04-2024, 09:16:50", + "recorded-date": "21-11-2024, 13:44:05", "recorded-content": { "fn_version_result": { "Architectures": [ @@ -14339,7 +14339,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_alias_naming": { - "recorded-date": "22-08-2024, 16:08:22", + "recorded-date": "21-11-2024, 13:45:11", "recorded-content": { "create_response": { "Architectures": [ @@ -18066,5 +18066,208 @@ } } } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_deletion_without_qualifier": { + "recorded-date": "21-11-2024, 13:44:17", + "recorded-content": { + "url_creation": { + "AuthType": "NONE", + "CreationTime": "date", + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionUrl": "lambda-url", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "url_with_alias_creation": { + "AuthType": "NONE", + "CreationTime": "date", + "FunctionArn": "arn::lambda::111111111111:function::test-alias", + "FunctionUrl": "lambda-url", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "get_url_config": { + "AuthType": "NONE", + "CreationTime": "date", + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionUrl": "lambda-url", + "InvokeMode": "BUFFERED", + "LastModifiedTime": "date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get_url_config_with_alias": { + "AuthType": "NONE", + "CreationTime": "date", + "FunctionArn": "arn::lambda::111111111111:function::test-alias", + "FunctionUrl": "lambda-url", + "InvokeMode": "BUFFERED", + "LastModifiedTime": "date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_function_url_config": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 204 + } + }, + "get_url_config_after_deletion": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "The resource you requested does not exist." + }, + "Message": "The resource you requested does not exist.", + "Type": "User", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "get_url_config_with_alias_after_deletion": { + "AuthType": "NONE", + "CreationTime": "date", + "FunctionArn": "arn::lambda::111111111111:function::test-alias", + "FunctionUrl": "lambda-url", + "InvokeMode": "BUFFERED", + "LastModifiedTime": "date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_non_existent_alias_deletion": { + "recorded-date": "21-11-2024, 13:44:51", + "recorded-content": { + "create_response": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "Environment": { + "Variables": { + "testenv": "staging" + } + }, + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "index.handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 128, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "python3.12", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "delete_alias_response": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 204 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_non_existent_alias_update": { + "recorded-date": "21-11-2024, 13:44:53", + "recorded-content": { + "create_response": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "Environment": { + "Variables": { + "testenv": "staging" + } + }, + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "index.handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 128, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "python3.12", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "update_alias_response": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Alias not found: arn::lambda::111111111111:function::non-existent" + }, + "Message": "Alias not found: arn::lambda::111111111111:function::non-existent", + "Type": "User", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } } } diff --git a/tests/aws/services/lambda_/test_lambda_api.validation.json b/tests/aws/services/lambda_/test_lambda_api.validation.json index d310fa0b3aca3..463cb8b483a46 100644 --- a/tests/aws/services/lambda_/test_lambda_api.validation.json +++ b/tests/aws/services/lambda_/test_lambda_api.validation.json @@ -15,13 +15,19 @@ "last_validated_date": "2024-04-10T09:19:34+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_alias_lifecycle": { - "last_validated_date": "2024-04-10T09:12:27+00:00" + "last_validated_date": "2024-11-21T13:44:48+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_alias_naming": { - "last_validated_date": "2024-08-22T16:08:21+00:00" + "last_validated_date": "2024-11-21T13:45:11+00:00" + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_non_existent_alias_deletion": { + "last_validated_date": "2024-11-21T13:44:51+00:00" + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_non_existent_alias_update": { + "last_validated_date": "2024-11-21T13:44:53+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_notfound_and_invalid_routingconfigs": { - "last_validated_date": "2024-04-10T09:12:41+00:00" + "last_validated_date": "2024-11-21T13:45:05+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventInvokeConfig::test_lambda_eventinvokeconfig_exceptions": { "last_validated_date": "2024-04-10T09:13:37+00:00" @@ -581,14 +587,17 @@ "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_versions": { "last_validated_date": "2024-10-24T15:22:38+00:00" }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_deletion_without_qualifier": { + "last_validated_date": "2024-11-21T13:44:17+00:00" + }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_exceptions": { - "last_validated_date": "2024-04-10T09:16:49+00:00" + "last_validated_date": "2024-11-21T13:44:04+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_lifecycle": { - "last_validated_date": "2024-04-10T09:16:59+00:00" + "last_validated_date": "2024-11-21T13:44:13+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_list_paging": { - "last_validated_date": "2024-04-10T09:16:55+00:00" + "last_validated_date": "2024-11-21T13:44:09+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_publish_version_on_create": { "last_validated_date": "2024-04-10T09:12:04+00:00" From 08ad92b199f40988a622fa5758ad56192e8e973b Mon Sep 17 00:00:00 2001 From: Luca Pivetta <36865043+Pive01@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:45:25 +0100 Subject: [PATCH 04/38] fix(providers): Removed cloudcontrol provider (#11920) --- localstack-core/localstack/services/providers.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/localstack-core/localstack/services/providers.py b/localstack-core/localstack/services/providers.py index f9703fe929a3c..7af73de74f1bf 100644 --- a/localstack-core/localstack/services/providers.py +++ b/localstack-core/localstack/services/providers.py @@ -41,14 +41,6 @@ def apigateway_legacy(): return Service.for_provider(provider, dispatch_table_factory=MotoFallbackDispatcher) -@aws_provider() -def cloudcontrol(): - from localstack.services.cloudcontrol.provider import CloudControlProvider - - provider = CloudControlProvider() - return Service.for_provider(provider) - - @aws_provider() def cloudformation(): from localstack.services.cloudformation.provider import CloudformationProvider From 4ff382958a6ee7ce7bb1a7922ab5f13c736fe360 Mon Sep 17 00:00:00 2001 From: LocalStack Bot <88328844+localstack-bot@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:40:11 +0100 Subject: [PATCH 05/38] Update ASF APIs, update provider signatures (#11918) Co-authored-by: LocalStack Bot Co-authored-by: Daniel Fangl --- .../localstack/aws/api/apigateway/__init__.py | 128 ++++- .../aws/api/cloudformation/__init__.py | 49 ++ .../localstack/aws/api/ec2/__init__.py | 425 +++++++++++++++ .../localstack/aws/api/lambda_/__init__.py | 29 ++ .../localstack/aws/api/logs/__init__.py | 486 +++++++++++++++++- .../localstack/aws/api/s3/__init__.py | 55 +- .../localstack/aws/api/ses/__init__.py | 9 + .../localstack/aws/api/ssm/__init__.py | 272 ++++++++++ .../services/apigateway/legacy/provider.py | 28 +- .../localstack/services/s3/provider.py | 8 + pyproject.toml | 4 +- requirements-base-runtime.txt | 4 +- requirements-dev.txt | 6 +- requirements-runtime.txt | 6 +- requirements-test.txt | 6 +- requirements-typehint.txt | 6 +- 16 files changed, 1491 insertions(+), 30 deletions(-) diff --git a/localstack-core/localstack/aws/api/apigateway/__init__.py b/localstack-core/localstack/aws/api/apigateway/__init__.py index 147e5a1cfad24..47bd84435db2f 100644 --- a/localstack-core/localstack/aws/api/apigateway/__init__.py +++ b/localstack-core/localstack/aws/api/apigateway/__init__.py @@ -15,6 +15,10 @@ String = str +class AccessAssociationSourceType(StrEnum): + VPCE = "VPCE" + + class ApiKeySourceType(StrEnum): HEADER = "HEADER" AUTHORIZER = "AUTHORIZER" @@ -145,6 +149,11 @@ class QuotaPeriodType(StrEnum): MONTH = "MONTH" +class ResourceOwner(StrEnum): + SELF = "SELF" + OTHER_ACCOUNTS = "OTHER_ACCOUNTS" + + class SecurityPolicy(StrEnum): TLS_1_0 = "TLS_1_0" TLS_1_2 = "TLS_1_2" @@ -373,6 +382,7 @@ class CreateApiKeyRequest(ServiceRequest): class CreateBasePathMappingRequest(ServiceRequest): domainName: String + domainNameId: Optional[String] basePath: Optional[String] restApiId: String stage: Optional[String] @@ -422,6 +432,13 @@ class CreateDocumentationVersionRequest(ServiceRequest): description: Optional[String] +class CreateDomainNameAccessAssociationRequest(ServiceRequest): + domainNameArn: String + accessAssociationSourceType: AccessAssociationSourceType + accessAssociationSource: String + tags: Optional[MapOfStringToString] + + class MutualTlsAuthenticationInput(TypedDict, total=False): truststoreUri: Optional[String] truststoreVersion: Optional[String] @@ -449,6 +466,7 @@ class CreateDomainNameRequest(ServiceRequest): securityPolicy: Optional[SecurityPolicy] mutualTlsAuthentication: Optional[MutualTlsAuthenticationInput] ownershipVerificationCertificateArn: Optional[String] + policy: Optional[String] class CreateModelRequest(ServiceRequest): @@ -542,6 +560,7 @@ class DeleteAuthorizerRequest(ServiceRequest): class DeleteBasePathMappingRequest(ServiceRequest): domainName: String + domainNameId: Optional[String] basePath: String @@ -564,8 +583,13 @@ class DeleteDocumentationVersionRequest(ServiceRequest): documentationVersion: String +class DeleteDomainNameAccessAssociationRequest(ServiceRequest): + domainNameAccessAssociationArn: String + + class DeleteDomainNameRequest(ServiceRequest): domainName: String + domainNameId: Optional[String] class DeleteGatewayResponseRequest(ServiceRequest): @@ -701,6 +725,8 @@ class MutualTlsAuthentication(TypedDict, total=False): class DomainName(TypedDict, total=False): domainName: Optional[String] + domainNameId: Optional[String] + domainNameArn: Optional[String] certificateName: Optional[String] certificateArn: Optional[String] certificateUploadDate: Optional[Timestamp] @@ -717,6 +743,24 @@ class DomainName(TypedDict, total=False): tags: Optional[MapOfStringToString] mutualTlsAuthentication: Optional[MutualTlsAuthentication] ownershipVerificationCertificateArn: Optional[String] + managementPolicy: Optional[String] + policy: Optional[String] + + +class DomainNameAccessAssociation(TypedDict, total=False): + domainNameAccessAssociationArn: Optional[String] + domainNameArn: Optional[String] + accessAssociationSourceType: Optional[AccessAssociationSourceType] + accessAssociationSource: Optional[String] + tags: Optional[MapOfStringToString] + + +ListOfDomainNameAccessAssociation = List[DomainNameAccessAssociation] + + +class DomainNameAccessAssociations(TypedDict, total=False): + position: Optional[String] + items: Optional[ListOfDomainNameAccessAssociation] ListOfDomainName = List[DomainName] @@ -794,11 +838,13 @@ class GetAuthorizersRequest(ServiceRequest): class GetBasePathMappingRequest(ServiceRequest): domainName: String + domainNameId: Optional[String] basePath: String class GetBasePathMappingsRequest(ServiceRequest): domainName: String + domainNameId: Optional[String] position: Optional[String] limit: Optional[NullableInteger] @@ -855,13 +901,21 @@ class GetDocumentationVersionsRequest(ServiceRequest): limit: Optional[NullableInteger] +class GetDomainNameAccessAssociationsRequest(ServiceRequest): + position: Optional[String] + limit: Optional[NullableInteger] + resourceOwner: Optional[ResourceOwner] + + class GetDomainNameRequest(ServiceRequest): domainName: String + domainNameId: Optional[String] class GetDomainNamesRequest(ServiceRequest): position: Optional[String] limit: Optional[NullableInteger] + resourceOwner: Optional[ResourceOwner] class GetExportRequest(ServiceRequest): @@ -1359,6 +1413,11 @@ class PutRestApiRequest(ServiceRequest): parameters: Optional[MapOfStringToString] +class RejectDomainNameAccessAssociationRequest(ServiceRequest): + domainNameAccessAssociationArn: String + domainNameArn: String + + class RequestValidators(TypedDict, total=False): position: Optional[String] items: Optional[ListOfRequestValidator] @@ -1466,6 +1525,7 @@ class UpdateAuthorizerRequest(ServiceRequest): class UpdateBasePathMappingRequest(ServiceRequest): domainName: String + domainNameId: Optional[String] basePath: String patchOperations: Optional[ListOfPatchOperation] @@ -1495,6 +1555,7 @@ class UpdateDocumentationVersionRequest(ServiceRequest): class UpdateDomainNameRequest(ServiceRequest): domainName: String + domainNameId: Optional[String] patchOperations: Optional[ListOfPatchOperation] @@ -1634,6 +1695,7 @@ def create_base_path_mapping( context: RequestContext, domain_name: String, rest_api_id: String, + domain_name_id: String = None, base_path: String = None, stage: String = None, **kwargs, @@ -1697,10 +1759,23 @@ def create_domain_name( security_policy: SecurityPolicy = None, mutual_tls_authentication: MutualTlsAuthenticationInput = None, ownership_verification_certificate_arn: String = None, + policy: String = None, **kwargs, ) -> DomainName: raise NotImplementedError + @handler("CreateDomainNameAccessAssociation") + def create_domain_name_access_association( + self, + context: RequestContext, + domain_name_arn: String, + access_association_source_type: AccessAssociationSourceType, + access_association_source: String, + tags: MapOfStringToString = None, + **kwargs, + ) -> DomainNameAccessAssociation: + raise NotImplementedError + @handler("CreateModel") def create_model( self, @@ -1824,7 +1899,12 @@ def delete_authorizer( @handler("DeleteBasePathMapping") def delete_base_path_mapping( - self, context: RequestContext, domain_name: String, base_path: String, **kwargs + self, + context: RequestContext, + domain_name: String, + base_path: String, + domain_name_id: String = None, + **kwargs, ) -> None: raise NotImplementedError @@ -1853,7 +1933,15 @@ def delete_documentation_version( raise NotImplementedError @handler("DeleteDomainName") - def delete_domain_name(self, context: RequestContext, domain_name: String, **kwargs) -> None: + def delete_domain_name( + self, context: RequestContext, domain_name: String, domain_name_id: String = None, **kwargs + ) -> None: + raise NotImplementedError + + @handler("DeleteDomainNameAccessAssociation") + def delete_domain_name_access_association( + self, context: RequestContext, domain_name_access_association_arn: String, **kwargs + ) -> None: raise NotImplementedError @handler("DeleteGatewayResponse") @@ -2022,7 +2110,12 @@ def get_authorizers( @handler("GetBasePathMapping") def get_base_path_mapping( - self, context: RequestContext, domain_name: String, base_path: String, **kwargs + self, + context: RequestContext, + domain_name: String, + base_path: String, + domain_name_id: String = None, + **kwargs, ) -> BasePathMapping: raise NotImplementedError @@ -2031,6 +2124,7 @@ def get_base_path_mappings( self, context: RequestContext, domain_name: String, + domain_name_id: String = None, position: String = None, limit: NullableInteger = None, **kwargs, @@ -2105,7 +2199,20 @@ def get_documentation_versions( raise NotImplementedError @handler("GetDomainName") - def get_domain_name(self, context: RequestContext, domain_name: String, **kwargs) -> DomainName: + def get_domain_name( + self, context: RequestContext, domain_name: String, domain_name_id: String = None, **kwargs + ) -> DomainName: + raise NotImplementedError + + @handler("GetDomainNameAccessAssociations") + def get_domain_name_access_associations( + self, + context: RequestContext, + position: String = None, + limit: NullableInteger = None, + resource_owner: ResourceOwner = None, + **kwargs, + ) -> DomainNameAccessAssociations: raise NotImplementedError @handler("GetDomainNames") @@ -2114,6 +2221,7 @@ def get_domain_names( context: RequestContext, position: String = None, limit: NullableInteger = None, + resource_owner: ResourceOwner = None, **kwargs, ) -> DomainNames: raise NotImplementedError @@ -2505,6 +2613,16 @@ def put_rest_api( ) -> RestApi: raise NotImplementedError + @handler("RejectDomainNameAccessAssociation") + def reject_domain_name_access_association( + self, + context: RequestContext, + domain_name_access_association_arn: String, + domain_name_arn: String, + **kwargs, + ) -> None: + raise NotImplementedError + @handler("TagResource") def tag_resource( self, context: RequestContext, resource_arn: String, tags: MapOfStringToString, **kwargs @@ -2583,6 +2701,7 @@ def update_base_path_mapping( context: RequestContext, domain_name: String, base_path: String, + domain_name_id: String = None, patch_operations: ListOfPatchOperation = None, **kwargs, ) -> BasePathMapping: @@ -2636,6 +2755,7 @@ def update_domain_name( self, context: RequestContext, domain_name: String, + domain_name_id: String = None, patch_operations: ListOfPatchOperation = None, **kwargs, ) -> DomainName: diff --git a/localstack-core/localstack/aws/api/cloudformation/__init__.py b/localstack-core/localstack/aws/api/cloudformation/__init__.py index db4ae73c7b7a2..ce08c6af010d5 100644 --- a/localstack-core/localstack/aws/api/cloudformation/__init__.py +++ b/localstack-core/localstack/aws/api/cloudformation/__init__.py @@ -44,6 +44,7 @@ GeneratedTemplateId = str GeneratedTemplateName = str HookInvocationCount = int +HookResultId = str HookStatusReason = str HookTargetTypeName = str HookType = str @@ -376,6 +377,13 @@ class IdentityProvider(StrEnum): Bitbucket = "Bitbucket" +class ListHookResultsTargetType(StrEnum): + CHANGE_SET = "CHANGE_SET" + STACK = "STACK" + RESOURCE = "RESOURCE" + CLOUD_CONTROL = "CLOUD_CONTROL" + + class OnFailure(StrEnum): DO_NOTHING = "DO_NOTHING" ROLLBACK = "ROLLBACK" @@ -693,6 +701,12 @@ class GeneratedTemplateNotFoundException(ServiceException): status_code: int = 404 +class HookResultNotFoundException(ServiceException): + code: str = "HookResultNotFound" + sender_fault: bool = True + status_code: int = 404 + + class InsufficientCapabilitiesException(ServiceException): code: str = "InsufficientCapabilitiesException" sender_fault: bool = True @@ -1974,6 +1988,17 @@ class GetTemplateSummaryOutput(TypedDict, total=False): Warnings: Optional[Warnings] +class HookResultSummary(TypedDict, total=False): + InvocationPoint: Optional[HookInvocationPoint] + FailureMode: Optional[HookFailureMode] + TypeName: Optional[HookTypeName] + TypeVersionId: Optional[HookTypeVersionId] + TypeConfigurationVersionId: Optional[HookTypeConfigurationVersionId] + Status: Optional[HookStatus] + HookStatusReason: Optional[HookStatusReason] + + +HookResultSummaries = List[HookResultSummary] StackIdList = List[StackId] @@ -2040,6 +2065,19 @@ class ListGeneratedTemplatesOutput(TypedDict, total=False): NextToken: Optional[NextToken] +class ListHookResultsInput(ServiceRequest): + TargetType: ListHookResultsTargetType + TargetId: HookResultId + NextToken: Optional[NextToken] + + +class ListHookResultsOutput(TypedDict, total=False): + TargetType: Optional[ListHookResultsTargetType] + TargetId: Optional[HookResultId] + HookResults: Optional[HookResultSummaries] + NextToken: Optional[NextToken] + + class ListImportsInput(ServiceRequest): ExportName: ExportName NextToken: Optional[NextToken] @@ -3201,6 +3239,17 @@ def list_generated_templates( ) -> ListGeneratedTemplatesOutput: raise NotImplementedError + @handler("ListHookResults") + def list_hook_results( + self, + context: RequestContext, + target_type: ListHookResultsTargetType, + target_id: HookResultId, + next_token: NextToken = None, + **kwargs, + ) -> ListHookResultsOutput: + raise NotImplementedError + @handler("ListImports") def list_imports( self, diff --git a/localstack-core/localstack/aws/api/ec2/__init__.py b/localstack-core/localstack/aws/api/ec2/__init__.py index 31ad71f764fe5..2a95b26d5c82e 100644 --- a/localstack-core/localstack/aws/api/ec2/__init__.py +++ b/localstack-core/localstack/aws/api/ec2/__init__.py @@ -62,6 +62,7 @@ DefaultingDhcpOptionsId = str DescribeAddressTransfersMaxResults = int DescribeByoipCidrsMaxResults = int +DescribeCapacityBlockExtensionOfferingsMaxResults = int DescribeCapacityBlockOfferingsMaxResults = int DescribeCapacityReservationBillingRequestsRequestMaxResults = int DescribeCapacityReservationFleetsMaxResults = int @@ -79,6 +80,7 @@ DescribeFastLaunchImagesRequestMaxResults = int DescribeFastSnapshotRestoresMaxResults = int DescribeFpgaImagesMaxResults = int +DescribeFutureCapacityMaxResults = int DescribeHostReservationsMaxResults = int DescribeIamInstanceProfileAssociationsMaxResults = int DescribeInstanceCreditSpecificationsMaxResults = int @@ -114,6 +116,7 @@ DescribeVerifiedAccessInstanceLoggingConfigurationsMaxResults = int DescribeVerifiedAccessInstancesMaxResults = int DescribeVerifiedAccessTrustProvidersMaxResults = int +DescribeVpcBlockPublicAccessExclusionsMaxResults = int DescribeVpcClassicLinkDnsSupportMaxResults = int DescribeVpcClassicLinkDnsSupportNextToken = str DescribeVpcPeeringConnectionsMaxResults = int @@ -336,6 +339,7 @@ VersionDescription = str VolumeId = str VolumeIdWithResolver = str +VpcBlockPublicAccessExclusionId = str VpcCidrAssociationId = str VpcEndpointId = str VpcEndpointServiceId = str @@ -560,6 +564,12 @@ class BgpStatus(StrEnum): down = "down" +class BlockPublicAccessMode(StrEnum): + off = "off" + block_bidirectional = "block-bidirectional" + block_ingress = "block-ingress" + + class BootModeType(StrEnum): legacy_bios = "legacy-bios" uefi = "uefi" @@ -618,6 +628,12 @@ class CancelSpotInstanceRequestState(StrEnum): completed = "completed" +class CapacityBlockExtensionStatus(StrEnum): + payment_pending = "payment-pending" + payment_failed = "payment-failed" + payment_succeeded = "payment-succeeded" + + class CapacityReservationBillingRequestStatus(StrEnum): pending = "pending" accepted = "accepted" @@ -627,6 +643,11 @@ class CapacityReservationBillingRequestStatus(StrEnum): expired = "expired" +class CapacityReservationDeliveryPreference(StrEnum): + fixed = "fixed" + incremental = "incremental" + + class CapacityReservationFleetState(StrEnum): submitted = "submitted" modifying = "modifying" @@ -661,6 +682,7 @@ class CapacityReservationInstancePlatform(StrEnum): class CapacityReservationPreference(StrEnum): + capacity_reservations_only = "capacity-reservations-only" open = "open" none = "none" @@ -674,6 +696,9 @@ class CapacityReservationState(StrEnum): scheduled = "scheduled" payment_pending = "payment-pending" payment_failed = "payment-failed" + assessing = "assessing" + delayed = "delayed" + unsupported = "unsupported" class CapacityReservationTenancy(StrEnum): @@ -770,6 +795,7 @@ class CpuManufacturer(StrEnum): intel = "intel" amd = "amd" amazon_web_services = "amazon-web-services" + apple = "apple" class CurrencyCodeValues(StrEnum): @@ -2160,6 +2186,17 @@ class InterfaceProtocolType(StrEnum): GRE = "GRE" +class InternetGatewayBlockMode(StrEnum): + off = "off" + block_bidirectional = "block-bidirectional" + block_ingress = "block-ingress" + + +class InternetGatewayExclusionMode(StrEnum): + allow_bidirectional = "allow-bidirectional" + allow_egress = "allow-egress" + + class IpAddressType(StrEnum): ipv4 = "ipv4" dualstack = "dualstack" @@ -3447,6 +3484,25 @@ class VpcAttributeName(StrEnum): enableNetworkAddressUsageMetrics = "enableNetworkAddressUsageMetrics" +class VpcBlockPublicAccessExclusionState(StrEnum): + create_in_progress = "create-in-progress" + create_complete = "create-complete" + create_failed = "create-failed" + update_in_progress = "update-in-progress" + update_complete = "update-complete" + update_failed = "update-failed" + delete_in_progress = "delete-in-progress" + delete_complete = "delete-complete" + disable_in_progress = "disable-in-progress" + disable_complete = "disable-complete" + + +class VpcBlockPublicAccessState(StrEnum): + default_state = "default-state" + update_in_progress = "update-in-progress" + update_complete = "update-complete" + + class VpcCidrBlockStateCode(StrEnum): associating = "associating" associated = "associated" @@ -4141,6 +4197,13 @@ class AddIpamOperatingRegion(TypedDict, total=False): AddIpamOperatingRegionSet = List[AddIpamOperatingRegion] +class AddIpamOrganizationalUnitExclusion(TypedDict, total=False): + OrganizationsEntityPath: Optional[String] + + +AddIpamOrganizationalUnitExclusionSet = List[AddIpamOrganizationalUnitExclusion] + + class AddPrefixListEntry(TypedDict, total=False): Cidr: String Description: Optional[String] @@ -5143,6 +5206,36 @@ class BaselineEbsBandwidthMbpsRequest(TypedDict, total=False): Max: Optional[Integer] +class PerformanceFactorReference(TypedDict, total=False): + InstanceFamily: Optional[String] + + +PerformanceFactorReferenceSet = List[PerformanceFactorReference] + + +class CpuPerformanceFactor(TypedDict, total=False): + References: Optional[PerformanceFactorReferenceSet] + + +class BaselinePerformanceFactors(TypedDict, total=False): + Cpu: Optional[CpuPerformanceFactor] + + +class PerformanceFactorReferenceRequest(TypedDict, total=False): + InstanceFamily: Optional[String] + + +PerformanceFactorReferenceSetRequest = List[PerformanceFactorReferenceRequest] + + +class CpuPerformanceFactorRequest(TypedDict, total=False): + References: Optional[PerformanceFactorReferenceSetRequest] + + +class BaselinePerformanceFactorsRequest(TypedDict, total=False): + Cpu: Optional[CpuPerformanceFactorRequest] + + BillingProductList = List[String] Blob = bytes @@ -5172,6 +5265,12 @@ class BlockDeviceMapping(TypedDict, total=False): BlockDeviceMappingList = List[BlockDeviceMapping] BlockDeviceMappingRequestList = List[BlockDeviceMapping] + + +class BlockPublicAccessStates(TypedDict, total=False): + InternetGatewayBlockMode: Optional[BlockPublicAccessMode] + + BootModeTypeList = List[BootModeType] BundleIdStringList = List[BundleId] @@ -5421,6 +5520,41 @@ class CapacityAllocation(TypedDict, total=False): CapacityAllocations = List[CapacityAllocation] +class CapacityBlockExtension(TypedDict, total=False): + CapacityReservationId: Optional[CapacityReservationId] + InstanceType: Optional[String] + InstanceCount: Optional[Integer] + AvailabilityZone: Optional[AvailabilityZoneName] + AvailabilityZoneId: Optional[AvailabilityZoneId] + CapacityBlockExtensionOfferingId: Optional[OfferingId] + CapacityBlockExtensionDurationHours: Optional[Integer] + CapacityBlockExtensionStatus: Optional[CapacityBlockExtensionStatus] + CapacityBlockExtensionPurchaseDate: Optional[MillisecondDateTime] + CapacityBlockExtensionStartDate: Optional[MillisecondDateTime] + CapacityBlockExtensionEndDate: Optional[MillisecondDateTime] + UpfrontFee: Optional[String] + CurrencyCode: Optional[String] + + +class CapacityBlockExtensionOffering(TypedDict, total=False): + CapacityBlockExtensionOfferingId: Optional[OfferingId] + InstanceType: Optional[String] + InstanceCount: Optional[Integer] + AvailabilityZone: Optional[AvailabilityZoneName] + AvailabilityZoneId: Optional[AvailabilityZoneId] + StartDate: Optional[MillisecondDateTime] + CapacityBlockExtensionStartDate: Optional[MillisecondDateTime] + CapacityBlockExtensionEndDate: Optional[MillisecondDateTime] + CapacityBlockExtensionDurationHours: Optional[Integer] + UpfrontFee: Optional[String] + CurrencyCode: Optional[String] + Tenancy: Optional[CapacityReservationTenancy] + + +CapacityBlockExtensionOfferingSet = List[CapacityBlockExtensionOffering] +CapacityBlockExtensionSet = List[CapacityBlockExtension] + + class CapacityBlockOffering(TypedDict, total=False): CapacityBlockOfferingId: Optional[OfferingId] InstanceType: Optional[String] @@ -5432,11 +5566,17 @@ class CapacityBlockOffering(TypedDict, total=False): UpfrontFee: Optional[String] CurrencyCode: Optional[String] Tenancy: Optional[CapacityReservationTenancy] + CapacityBlockDurationMinutes: Optional[Integer] CapacityBlockOfferingSet = List[CapacityBlockOffering] +class CapacityReservationCommitmentInfo(TypedDict, total=False): + CommittedInstanceCount: Optional[Integer] + CommitmentEndDate: Optional[MillisecondDateTime] + + class CapacityReservation(TypedDict, total=False): CapacityReservationId: Optional[String] OwnerId: Optional[String] @@ -5463,6 +5603,8 @@ class CapacityReservation(TypedDict, total=False): CapacityAllocations: Optional[CapacityAllocations] ReservationType: Optional[CapacityReservationType] UnusedReservationBillingOwnerId: Optional[AccountID] + CommitmentInfo: Optional[CapacityReservationCommitmentInfo] + DeliveryPreference: Optional[CapacityReservationDeliveryPreference] class CapacityReservationInfo(TypedDict, total=False): @@ -5482,6 +5624,7 @@ class CapacityReservationBillingRequest(TypedDict, total=False): CapacityReservationBillingRequestSet = List[CapacityReservationBillingRequest] +CapacityReservationCommitmentDuration = int class FleetCapacityReservation(TypedDict, total=False): @@ -6063,6 +6206,9 @@ class CreateCapacityReservationRequest(ServiceRequest): DryRun: Optional[Boolean] OutpostArn: Optional[OutpostArn] PlacementGroupArn: Optional[PlacementGroupArn] + StartDate: Optional[MillisecondDateTime] + CommitmentDuration: Optional[CapacityReservationCommitmentDuration] + DeliveryPreference: Optional[CapacityReservationDeliveryPreference] class CreateCapacityReservationResult(TypedDict, total=False): @@ -6197,6 +6343,7 @@ class Subnet(TypedDict, total=False): EnableDns64: Optional[Boolean] Ipv6Native: Optional[Boolean] PrivateDnsNameOptionsOnLaunch: Optional[PrivateDnsNameOptionsOnLaunch] + BlockPublicAccessStates: Optional[BlockPublicAccessStates] SubnetId: Optional[String] State: Optional[SubnetState] VpcId: Optional[String] @@ -6226,6 +6373,7 @@ class Vpc(TypedDict, total=False): CidrBlockAssociationSet: Optional[VpcCidrBlockAssociationSet] IsDefault: Optional[Boolean] Tags: Optional[TagList] + BlockPublicAccessStates: Optional[BlockPublicAccessStates] VpcId: Optional[String] State: Optional[VpcState] CidrBlock: Optional[String] @@ -6360,6 +6508,7 @@ class InstanceRequirements(TypedDict, total=False): NetworkBandwidthGbps: Optional[NetworkBandwidthGbps] AllowedInstanceTypes: Optional[AllowedInstanceTypeSet] MaxSpotPriceAsPercentageOfOptimalOnDemandPrice: Optional[Integer] + BaselinePerformanceFactors: Optional[BaselinePerformanceFactors] class PlacementResponse(TypedDict, total=False): @@ -6474,6 +6623,7 @@ class InstanceRequirementsRequest(TypedDict, total=False): NetworkBandwidthGbps: Optional[NetworkBandwidthGbpsRequest] AllowedInstanceTypes: Optional[AllowedInstanceTypeSet] MaxSpotPriceAsPercentageOfOptimalOnDemandPrice: Optional[Integer] + BaselinePerformanceFactors: Optional[BaselinePerformanceFactorsRequest] class Placement(TypedDict, total=False): @@ -6877,6 +7027,13 @@ class CreateIpamResourceDiscoveryRequest(ServiceRequest): ClientToken: Optional[String] +class IpamOrganizationalUnitExclusion(TypedDict, total=False): + OrganizationsEntityPath: Optional[String] + + +IpamOrganizationalUnitExclusionSet = List[IpamOrganizationalUnitExclusion] + + class IpamOperatingRegion(TypedDict, total=False): RegionName: Optional[String] @@ -6894,6 +7051,7 @@ class IpamResourceDiscovery(TypedDict, total=False): IsDefault: Optional[Boolean] State: Optional[IpamResourceDiscoveryState] Tags: Optional[TagList] + OrganizationalUnitExclusions: Optional[IpamOrganizationalUnitExclusionSet] class CreateIpamResourceDiscoveryResult(TypedDict, total=False): @@ -6958,6 +7116,10 @@ class CreateKeyPairRequest(ServiceRequest): DryRun: Optional[Boolean] +class OperatorRequest(TypedDict, total=False): + Principal: Optional[String] + + class LaunchTemplateInstanceMaintenanceOptionsRequest(TypedDict, total=False): AutoRecovery: Optional[LaunchTemplateAutoRecoveryState] @@ -7190,6 +7352,7 @@ class RequestLaunchTemplateData(TypedDict, total=False): PrivateDnsNameOptions: Optional[LaunchTemplatePrivateDnsNameOptionsRequest] MaintenanceOptions: Optional[LaunchTemplateInstanceMaintenanceOptionsRequest] DisableApiStop: Optional[Boolean] + Operator: Optional[OperatorRequest] class CreateLaunchTemplateRequest(ServiceRequest): @@ -7198,6 +7361,7 @@ class CreateLaunchTemplateRequest(ServiceRequest): LaunchTemplateName: LaunchTemplateName VersionDescription: Optional[VersionDescription] LaunchTemplateData: RequestLaunchTemplateData + Operator: Optional[OperatorRequest] TagSpecifications: Optional[TagSpecificationList] @@ -7213,6 +7377,11 @@ class ValidationWarning(TypedDict, total=False): Errors: Optional[ErrorSet] +class OperatorResponse(TypedDict, total=False): + Managed: Optional[Boolean] + Principal: Optional[String] + + class LaunchTemplate(TypedDict, total=False): LaunchTemplateId: Optional[String] LaunchTemplateName: Optional[LaunchTemplateName] @@ -7221,6 +7390,7 @@ class LaunchTemplate(TypedDict, total=False): DefaultVersionNumber: Optional[Long] LatestVersionNumber: Optional[Long] Tags: Optional[TagList] + Operator: Optional[OperatorResponse] class CreateLaunchTemplateResult(TypedDict, total=False): @@ -7463,6 +7633,7 @@ class ResponseLaunchTemplateData(TypedDict, total=False): PrivateDnsNameOptions: Optional[LaunchTemplatePrivateDnsNameOptions] MaintenanceOptions: Optional[LaunchTemplateInstanceMaintenanceOptions] DisableApiStop: Optional[Boolean] + Operator: Optional[OperatorResponse] class LaunchTemplateVersion(TypedDict, total=False): @@ -7474,6 +7645,7 @@ class LaunchTemplateVersion(TypedDict, total=False): CreatedBy: Optional[String] DefaultVersion: Optional[Boolean] LaunchTemplateData: Optional[ResponseLaunchTemplateData] + Operator: Optional[OperatorResponse] class CreateLaunchTemplateVersionResult(TypedDict, total=False): @@ -7837,6 +8009,7 @@ class CreateNetworkInterfaceRequest(ServiceRequest): ClientToken: Optional[String] EnablePrimaryIpv6: Optional[Boolean] ConnectionTrackingSpecification: Optional[ConnectionTrackingSpecificationRequest] + Operator: Optional[OperatorRequest] SubnetId: SubnetId Description: Optional[String] PrivateIpAddress: Optional[String] @@ -7923,6 +8096,7 @@ class NetworkInterface(TypedDict, total=False): DenyAllIgwTraffic: Optional[Boolean] Ipv6Native: Optional[Boolean] Ipv6Address: Optional[String] + Operator: Optional[OperatorResponse] class CreateNetworkInterfaceResult(TypedDict, total=False): @@ -8902,9 +9076,34 @@ class CreateVolumeRequest(ServiceRequest): MultiAttachEnabled: Optional[Boolean] Throughput: Optional[Integer] ClientToken: Optional[String] + Operator: Optional[OperatorRequest] DryRun: Optional[Boolean] +class CreateVpcBlockPublicAccessExclusionRequest(ServiceRequest): + DryRun: Optional[Boolean] + SubnetId: Optional[SubnetId] + VpcId: Optional[VpcId] + InternetGatewayExclusionMode: InternetGatewayExclusionMode + TagSpecifications: Optional[TagSpecificationList] + + +class VpcBlockPublicAccessExclusion(TypedDict, total=False): + ExclusionId: Optional[VpcBlockPublicAccessExclusionId] + InternetGatewayExclusionMode: Optional[InternetGatewayExclusionMode] + ResourceArn: Optional[ResourceArn] + State: Optional[VpcBlockPublicAccessExclusionState] + Reason: Optional[String] + CreationTimestamp: Optional[MillisecondDateTime] + LastUpdateTimestamp: Optional[MillisecondDateTime] + DeletionTimestamp: Optional[MillisecondDateTime] + Tags: Optional[TagList] + + +class CreateVpcBlockPublicAccessExclusionResult(TypedDict, total=False): + VpcBlockPublicAccessExclusion: Optional[VpcBlockPublicAccessExclusion] + + class CreateVpcEndpointConnectionNotificationRequest(ServiceRequest): DryRun: Optional[Boolean] ServiceId: Optional[VpcEndpointServiceId] @@ -10063,6 +10262,15 @@ class DeleteVolumeRequest(ServiceRequest): DryRun: Optional[Boolean] +class DeleteVpcBlockPublicAccessExclusionRequest(ServiceRequest): + DryRun: Optional[Boolean] + ExclusionId: VpcBlockPublicAccessExclusionId + + +class DeleteVpcBlockPublicAccessExclusionResult(TypedDict, total=False): + VpcBlockPublicAccessExclusion: Optional[VpcBlockPublicAccessExclusion] + + class DeleteVpcEndpointConnectionNotificationsRequest(ServiceRequest): DryRun: Optional[Boolean] ConnectionNotificationIds: ConnectionNotificationIdsList @@ -10374,6 +10582,32 @@ class DescribeByoipCidrsResult(TypedDict, total=False): NextToken: Optional[String] +class DescribeCapacityBlockExtensionHistoryRequest(ServiceRequest): + CapacityReservationIds: Optional[CapacityReservationIdSet] + NextToken: Optional[String] + MaxResults: Optional[DescribeFutureCapacityMaxResults] + Filters: Optional[FilterList] + DryRun: Optional[Boolean] + + +class DescribeCapacityBlockExtensionHistoryResult(TypedDict, total=False): + CapacityBlockExtensions: Optional[CapacityBlockExtensionSet] + NextToken: Optional[String] + + +class DescribeCapacityBlockExtensionOfferingsRequest(ServiceRequest): + DryRun: Optional[Boolean] + CapacityBlockExtensionDurationHours: Integer + CapacityReservationId: CapacityReservationId + NextToken: Optional[String] + MaxResults: Optional[DescribeCapacityBlockExtensionOfferingsMaxResults] + + +class DescribeCapacityBlockExtensionOfferingsResult(TypedDict, total=False): + CapacityBlockExtensionOfferings: Optional[CapacityBlockExtensionOfferingSet] + NextToken: Optional[String] + + class DescribeCapacityBlockOfferingsRequest(ServiceRequest): DryRun: Optional[Boolean] InstanceType: Optional[String] @@ -11486,6 +11720,7 @@ class InstanceImageMetadata(TypedDict, total=False): OwnerId: Optional[String] Tags: Optional[TagList] ImageMetadata: Optional[ImageMetadata] + Operator: Optional[OperatorResponse] InstanceImageMetadataList = List[InstanceImageMetadata] @@ -11548,6 +11783,7 @@ class InstanceStatusEvent(TypedDict, total=False): class InstanceStatus(TypedDict, total=False): AvailabilityZone: Optional[String] OutpostArn: Optional[String] + Operator: Optional[OperatorResponse] Events: Optional[InstanceStatusEventList] InstanceId: Optional[String] InstanceState: Optional[InstanceState] @@ -12001,6 +12237,7 @@ class InstanceNetworkInterface(TypedDict, total=False): Ipv4Prefixes: Optional[InstanceIpv4PrefixList] Ipv6Prefixes: Optional[InstanceIpv6PrefixList] ConnectionTrackingConfiguration: Optional[ConnectionTrackingSpecificationResponse] + Operator: Optional[OperatorResponse] InstanceNetworkInterfaceList = List[InstanceNetworkInterface] @@ -12033,6 +12270,7 @@ class EbsInstanceBlockDevice(TypedDict, total=False): VolumeId: Optional[String] AssociatedResource: Optional[String] VolumeOwnerId: Optional[String] + Operator: Optional[OperatorResponse] class InstanceBlockDeviceMapping(TypedDict, total=False): @@ -12081,6 +12319,7 @@ class Instance(TypedDict, total=False): TpmSupport: Optional[String] MaintenanceOptions: Optional[InstanceMaintenanceOptions] CurrentInstanceBootMode: Optional[InstanceBootModeValues] + Operator: Optional[OperatorResponse] InstanceId: Optional[String] ImageId: Optional[String] State: Optional[InstanceState] @@ -14412,6 +14651,7 @@ class Volume(TypedDict, total=False): MultiAttachEnabled: Optional[Boolean] Throughput: Optional[Integer] SseType: Optional[SSEType] + Operator: Optional[OperatorResponse] VolumeId: Optional[String] Size: Optional[Integer] SnapshotId: Optional[String] @@ -14444,6 +14684,42 @@ class DescribeVpcAttributeResult(TypedDict, total=False): VpcId: Optional[String] +VpcBlockPublicAccessExclusionIdList = List[VpcBlockPublicAccessExclusionId] + + +class DescribeVpcBlockPublicAccessExclusionsRequest(ServiceRequest): + DryRun: Optional[Boolean] + Filters: Optional[FilterList] + ExclusionIds: Optional[VpcBlockPublicAccessExclusionIdList] + NextToken: Optional[String] + MaxResults: Optional[DescribeVpcBlockPublicAccessExclusionsMaxResults] + + +VpcBlockPublicAccessExclusionList = List[VpcBlockPublicAccessExclusion] + + +class DescribeVpcBlockPublicAccessExclusionsResult(TypedDict, total=False): + VpcBlockPublicAccessExclusions: Optional[VpcBlockPublicAccessExclusionList] + NextToken: Optional[String] + + +class DescribeVpcBlockPublicAccessOptionsRequest(ServiceRequest): + DryRun: Optional[Boolean] + + +class VpcBlockPublicAccessOptions(TypedDict, total=False): + AwsAccountId: Optional[String] + AwsRegion: Optional[String] + State: Optional[VpcBlockPublicAccessState] + InternetGatewayBlockMode: Optional[InternetGatewayBlockMode] + Reason: Optional[String] + LastUpdateTimestamp: Optional[MillisecondDateTime] + + +class DescribeVpcBlockPublicAccessOptionsResult(TypedDict, total=False): + VpcBlockPublicAccessOptions: Optional[VpcBlockPublicAccessOptions] + + VpcClassicLinkIdList = List[VpcId] @@ -15735,6 +16011,7 @@ class IpamDiscoveredAccount(TypedDict, total=False): FailureReason: Optional[IpamDiscoveryFailureReason] LastAttemptedDiscoveryTime: Optional[MillisecondDateTime] LastSuccessfulDiscoveryTime: Optional[MillisecondDateTime] + OrganizationalUnitId: Optional[String] IpamDiscoveredAccountSet = List[IpamDiscoveredAccount] @@ -17114,12 +17391,21 @@ class ModifyIpamResourceCidrResult(TypedDict, total=False): IpamResourceCidr: Optional[IpamResourceCidr] +class RemoveIpamOrganizationalUnitExclusion(TypedDict, total=False): + OrganizationsEntityPath: Optional[String] + + +RemoveIpamOrganizationalUnitExclusionSet = List[RemoveIpamOrganizationalUnitExclusion] + + class ModifyIpamResourceDiscoveryRequest(ServiceRequest): DryRun: Optional[Boolean] IpamResourceDiscoveryId: IpamResourceDiscoveryId Description: Optional[String] AddOperatingRegions: Optional[AddIpamOperatingRegionSet] RemoveOperatingRegions: Optional[RemoveIpamOperatingRegionSet] + AddOrganizationalUnitExclusions: Optional[AddIpamOrganizationalUnitExclusionSet] + RemoveOrganizationalUnitExclusions: Optional[RemoveIpamOrganizationalUnitExclusionSet] class ModifyIpamResourceDiscoveryResult(TypedDict, total=False): @@ -17586,6 +17872,25 @@ class ModifyVpcAttributeRequest(ServiceRequest): EnableNetworkAddressUsageMetrics: Optional[AttributeBooleanValue] +class ModifyVpcBlockPublicAccessExclusionRequest(ServiceRequest): + DryRun: Optional[Boolean] + ExclusionId: VpcBlockPublicAccessExclusionId + InternetGatewayExclusionMode: InternetGatewayExclusionMode + + +class ModifyVpcBlockPublicAccessExclusionResult(TypedDict, total=False): + VpcBlockPublicAccessExclusion: Optional[VpcBlockPublicAccessExclusion] + + +class ModifyVpcBlockPublicAccessOptionsRequest(ServiceRequest): + DryRun: Optional[Boolean] + InternetGatewayBlockMode: InternetGatewayBlockMode + + +class ModifyVpcBlockPublicAccessOptionsResult(TypedDict, total=False): + VpcBlockPublicAccessOptions: Optional[VpcBlockPublicAccessOptions] + + class ModifyVpcEndpointConnectionNotificationRequest(ServiceRequest): DryRun: Optional[Boolean] ConnectionNotificationId: ConnectionNotificationId @@ -17874,6 +18179,16 @@ class ProvisionPublicIpv4PoolCidrResult(TypedDict, total=False): PoolAddressRange: Optional[PublicIpv4PoolRange] +class PurchaseCapacityBlockExtensionRequest(ServiceRequest): + CapacityBlockExtensionOfferingId: OfferingId + CapacityReservationId: CapacityReservationId + DryRun: Optional[Boolean] + + +class PurchaseCapacityBlockExtensionResult(TypedDict, total=False): + CapacityBlockExtensions: Optional[CapacityBlockExtensionSet] + + class PurchaseCapacityBlockRequest(ServiceRequest): DryRun: Optional[Boolean] TagSpecifications: Optional[TagSpecificationList] @@ -18469,6 +18784,7 @@ class RunInstancesRequest(ServiceRequest): MaintenanceOptions: Optional[InstanceMaintenanceOptionsRequest] DisableApiStop: Optional[Boolean] EnablePrimaryIpv6: Optional[Boolean] + Operator: Optional[OperatorRequest] DryRun: Optional[Boolean] DisableApiTermination: Optional[Boolean] InstanceInitiatedShutdownBehavior: Optional[ShutdownBehavior] @@ -19531,6 +19847,9 @@ def create_capacity_reservation( dry_run: Boolean = None, outpost_arn: OutpostArn = None, placement_group_arn: PlacementGroupArn = None, + start_date: MillisecondDateTime = None, + commitment_duration: CapacityReservationCommitmentDuration = None, + delivery_preference: CapacityReservationDeliveryPreference = None, **kwargs, ) -> CreateCapacityReservationResult: raise NotImplementedError @@ -19893,6 +20212,7 @@ def create_launch_template( dry_run: Boolean = None, client_token: String = None, version_description: VersionDescription = None, + operator: OperatorRequest = None, tag_specifications: TagSpecificationList = None, **kwargs, ) -> CreateLaunchTemplateResult: @@ -20073,6 +20393,7 @@ def create_network_interface( client_token: String = None, enable_primary_ipv6: Boolean = None, connection_tracking_specification: ConnectionTrackingSpecificationRequest = None, + operator: OperatorRequest = None, description: String = None, private_ip_address: String = None, groups: SecurityGroupIdStringList = None, @@ -20600,6 +20921,7 @@ def create_volume( multi_attach_enabled: Boolean = None, throughput: Integer = None, client_token: String = None, + operator: OperatorRequest = None, dry_run: Boolean = None, **kwargs, ) -> Volume: @@ -20625,6 +20947,19 @@ def create_vpc( ) -> CreateVpcResult: raise NotImplementedError + @handler("CreateVpcBlockPublicAccessExclusion") + def create_vpc_block_public_access_exclusion( + self, + context: RequestContext, + internet_gateway_exclusion_mode: InternetGatewayExclusionMode, + dry_run: Boolean = None, + subnet_id: SubnetId = None, + vpc_id: VpcId = None, + tag_specifications: TagSpecificationList = None, + **kwargs, + ) -> CreateVpcBlockPublicAccessExclusionResult: + raise NotImplementedError + @handler("CreateVpcEndpoint") def create_vpc_endpoint( self, @@ -21393,6 +21728,16 @@ def delete_vpc( ) -> None: raise NotImplementedError + @handler("DeleteVpcBlockPublicAccessExclusion") + def delete_vpc_block_public_access_exclusion( + self, + context: RequestContext, + exclusion_id: VpcBlockPublicAccessExclusionId, + dry_run: Boolean = None, + **kwargs, + ) -> DeleteVpcBlockPublicAccessExclusionResult: + raise NotImplementedError + @handler("DeleteVpcEndpointConnectionNotifications") def delete_vpc_endpoint_connection_notifications( self, @@ -21642,6 +21987,32 @@ def describe_byoip_cidrs( ) -> DescribeByoipCidrsResult: raise NotImplementedError + @handler("DescribeCapacityBlockExtensionHistory") + def describe_capacity_block_extension_history( + self, + context: RequestContext, + capacity_reservation_ids: CapacityReservationIdSet = None, + next_token: String = None, + max_results: DescribeFutureCapacityMaxResults = None, + filters: FilterList = None, + dry_run: Boolean = None, + **kwargs, + ) -> DescribeCapacityBlockExtensionHistoryResult: + raise NotImplementedError + + @handler("DescribeCapacityBlockExtensionOfferings") + def describe_capacity_block_extension_offerings( + self, + context: RequestContext, + capacity_block_extension_duration_hours: Integer, + capacity_reservation_id: CapacityReservationId, + dry_run: Boolean = None, + next_token: String = None, + max_results: DescribeCapacityBlockExtensionOfferingsMaxResults = None, + **kwargs, + ) -> DescribeCapacityBlockExtensionOfferingsResult: + raise NotImplementedError + @handler("DescribeCapacityBlockOfferings") def describe_capacity_block_offerings( self, @@ -23357,6 +23728,25 @@ def describe_vpc_attribute( ) -> DescribeVpcAttributeResult: raise NotImplementedError + @handler("DescribeVpcBlockPublicAccessExclusions") + def describe_vpc_block_public_access_exclusions( + self, + context: RequestContext, + dry_run: Boolean = None, + filters: FilterList = None, + exclusion_ids: VpcBlockPublicAccessExclusionIdList = None, + next_token: String = None, + max_results: DescribeVpcBlockPublicAccessExclusionsMaxResults = None, + **kwargs, + ) -> DescribeVpcBlockPublicAccessExclusionsResult: + raise NotImplementedError + + @handler("DescribeVpcBlockPublicAccessOptions") + def describe_vpc_block_public_access_options( + self, context: RequestContext, dry_run: Boolean = None, **kwargs + ) -> DescribeVpcBlockPublicAccessOptionsResult: + raise NotImplementedError + @handler("DescribeVpcClassicLink") def describe_vpc_classic_link( self, @@ -25132,6 +25522,8 @@ def modify_ipam_resource_discovery( description: String = None, add_operating_regions: AddIpamOperatingRegionSet = None, remove_operating_regions: RemoveIpamOperatingRegionSet = None, + add_organizational_unit_exclusions: AddIpamOrganizationalUnitExclusionSet = None, + remove_organizational_unit_exclusions: RemoveIpamOrganizationalUnitExclusionSet = None, **kwargs, ) -> ModifyIpamResourceDiscoveryResult: raise NotImplementedError @@ -25513,6 +25905,27 @@ def modify_vpc_attribute( ) -> None: raise NotImplementedError + @handler("ModifyVpcBlockPublicAccessExclusion") + def modify_vpc_block_public_access_exclusion( + self, + context: RequestContext, + exclusion_id: VpcBlockPublicAccessExclusionId, + internet_gateway_exclusion_mode: InternetGatewayExclusionMode, + dry_run: Boolean = None, + **kwargs, + ) -> ModifyVpcBlockPublicAccessExclusionResult: + raise NotImplementedError + + @handler("ModifyVpcBlockPublicAccessOptions") + def modify_vpc_block_public_access_options( + self, + context: RequestContext, + internet_gateway_block_mode: InternetGatewayBlockMode, + dry_run: Boolean = None, + **kwargs, + ) -> ModifyVpcBlockPublicAccessOptionsResult: + raise NotImplementedError + @handler("ModifyVpcEndpoint") def modify_vpc_endpoint( self, @@ -25773,6 +26186,17 @@ def purchase_capacity_block( ) -> PurchaseCapacityBlockResult: raise NotImplementedError + @handler("PurchaseCapacityBlockExtension") + def purchase_capacity_block_extension( + self, + context: RequestContext, + capacity_block_extension_offering_id: OfferingId, + capacity_reservation_id: CapacityReservationId, + dry_run: Boolean = None, + **kwargs, + ) -> PurchaseCapacityBlockExtensionResult: + raise NotImplementedError + @handler("PurchaseHostReservation") def purchase_host_reservation( self, @@ -26305,6 +26729,7 @@ def run_instances( maintenance_options: InstanceMaintenanceOptionsRequest = None, disable_api_stop: Boolean = None, enable_primary_ipv6: Boolean = None, + operator: OperatorRequest = None, dry_run: Boolean = None, disable_api_termination: Boolean = None, instance_initiated_shutdown_behavior: ShutdownBehavior = None, diff --git a/localstack-core/localstack/aws/api/lambda_/__init__.py b/localstack-core/localstack/aws/api/lambda_/__init__.py index 2da164e8ec6e7..9e4551cf028bc 100644 --- a/localstack-core/localstack/aws/api/lambda_/__init__.py +++ b/localstack-core/localstack/aws/api/lambda_/__init__.py @@ -56,11 +56,13 @@ MaximumBatchingWindowInSeconds = int MaximumConcurrency = int MaximumEventAgeInSeconds = int +MaximumNumberOfPollers = int MaximumRecordAgeInSeconds = int MaximumRetryAttempts = int MaximumRetryAttemptsEventSourceMapping = int MemorySize = int Method = str +MinimumNumberOfPollers = int NameSpacedFunctionArn = str NamespacedFunctionName = str NamespacedStatementId = str @@ -130,6 +132,10 @@ class EndPointType(StrEnum): KAFKA_BOOTSTRAP_SERVERS = "KAFKA_BOOTSTRAP_SERVERS" +class EventSourceMappingMetric(StrEnum): + EventCount = "EventCount" + + class EventSourcePosition(StrEnum): TRIM_HORIZON = "TRIM_HORIZON" LATEST = "LATEST" @@ -266,6 +272,7 @@ class Runtime(StrEnum): python3_12 = "python3.12" java21 = "java21" python3_13 = "python3.13" + nodejs22_x = "nodejs22.x" class SnapStartApplyOn(StrEnum): @@ -763,6 +770,18 @@ class CreateCodeSigningConfigResponse(TypedDict, total=False): CodeSigningConfig: CodeSigningConfig +class ProvisionedPollerConfig(TypedDict, total=False): + MinimumPollers: Optional[MinimumNumberOfPollers] + MaximumPollers: Optional[MaximumNumberOfPollers] + + +EventSourceMappingMetricList = List[EventSourceMappingMetric] + + +class EventSourceMappingMetricsConfig(TypedDict, total=False): + Metrics: Optional[EventSourceMappingMetricList] + + class DocumentDBEventSourceConfig(TypedDict, total=False): DatabaseName: Optional[DatabaseName] CollectionName: Optional[CollectionName] @@ -849,6 +868,8 @@ class CreateEventSourceMappingRequest(ServiceRequest): ScalingConfig: Optional[ScalingConfig] DocumentDBEventSourceConfig: Optional[DocumentDBEventSourceConfig] KMSKeyArn: Optional[KMSKeyArn] + MetricsConfig: Optional[EventSourceMappingMetricsConfig] + ProvisionedPollerConfig: Optional[ProvisionedPollerConfig] class LoggingConfig(TypedDict, total=False): @@ -1058,6 +1079,8 @@ class EventSourceMappingConfiguration(TypedDict, total=False): KMSKeyArn: Optional[KMSKeyArn] FilterCriteriaError: Optional[FilterCriteriaError] EventSourceMappingArn: Optional[EventSourceMappingArn] + MetricsConfig: Optional[EventSourceMappingMetricsConfig] + ProvisionedPollerConfig: Optional[ProvisionedPollerConfig] EventSourceMappingsList = List[EventSourceMappingConfiguration] @@ -1736,6 +1759,8 @@ class UpdateEventSourceMappingRequest(ServiceRequest): ScalingConfig: Optional[ScalingConfig] DocumentDBEventSourceConfig: Optional[DocumentDBEventSourceConfig] KMSKeyArn: Optional[KMSKeyArn] + MetricsConfig: Optional[EventSourceMappingMetricsConfig] + ProvisionedPollerConfig: Optional[ProvisionedPollerConfig] class UpdateFunctionCodeRequest(ServiceRequest): @@ -1892,6 +1917,8 @@ def create_event_source_mapping( scaling_config: ScalingConfig = None, document_db_event_source_config: DocumentDBEventSourceConfig = None, kms_key_arn: KMSKeyArn = None, + metrics_config: EventSourceMappingMetricsConfig = None, + provisioned_poller_config: ProvisionedPollerConfig = None, **kwargs, ) -> EventSourceMappingConfiguration: raise NotImplementedError @@ -2494,6 +2521,8 @@ def update_event_source_mapping( scaling_config: ScalingConfig = None, document_db_event_source_config: DocumentDBEventSourceConfig = None, kms_key_arn: KMSKeyArn = None, + metrics_config: EventSourceMappingMetricsConfig = None, + provisioned_poller_config: ProvisionedPollerConfig = None, **kwargs, ) -> EventSourceMappingConfiguration: raise NotImplementedError diff --git a/localstack-core/localstack/aws/api/logs/__init__.py b/localstack-core/localstack/aws/api/logs/__init__.py index 95c50a8aeb050..4b8a1920194e1 100644 --- a/localstack-core/localstack/aws/api/logs/__init__.py +++ b/localstack-core/localstack/aws/api/logs/__init__.py @@ -6,17 +6,21 @@ AccessPolicy = str AccountId = str AccountPolicyDocument = str +AddKeyValue = str AllowedActionForAllowVendedLogsDeliveryForResource = str AmazonResourceName = str AnomalyDetectorArn = str AnomalyId = str +ApplyOnTransformedLogs = bool Arn = str Baseline = bool Boolean = bool ClientToken = str +Column = str DataProtectionPolicyDocument = str Days = int DefaultValue = float +Delimiter = str DeliveryDestinationName = str DeliveryDestinationPolicy = str DeliveryId = str @@ -27,6 +31,7 @@ DescribeQueriesMaxResults = int Description = str DestinationArn = str +DestinationField = str DestinationName = str DetectorName = str DimensionsKey = str @@ -48,18 +53,27 @@ Field = str FieldDelimiter = str FieldHeader = str +FieldIndexName = str FilterCount = int FilterName = str FilterPattern = str +Flatten = bool ForceUpdate = bool +FromKey = str +GrokMatch = str IncludeLinkedAccounts = bool InferredTokenName = str Integer = int Interleaved = bool IsSampled = bool +Key = str +KeyPrefix = str +KeyValueDelimiter = str KmsKeyId = str ListAnomaliesLimit = int ListLogAnomalyDetectorsLimit = int +ListLogGroupsForQueryMaxResults = int +Locale = str LogEventIndex = int LogGroupArn = str LogGroupIdentifier = str @@ -69,11 +83,15 @@ LogStreamName = str LogStreamSearchedCompletely = bool LogType = str +MatchPattern = str Message = str MetricName = str MetricNamespace = str MetricValue = str NextToken = str +NonMatchValue = str +OverwriteIfExists = bool +ParserFieldDelimiter = str PatternId = str PatternRegex = str PatternString = str @@ -87,6 +105,8 @@ QueryId = str QueryListMaxResults = int QueryString = str +QuoteCharacter = str +RenameTo = str RequestId = str ResourceIdentifier = str ResourceType = str @@ -95,17 +115,26 @@ SequenceToken = str Service = str SessionId = str +Source = str +SourceTimezone = str StartFromHead = bool StatsValue = float Success = bool TagKey = str TagValue = str +Target = str TargetArn = str +TargetFormat = str +TargetTimezone = str Time = str +ToKey = str Token = str TokenString = str +TransformedEventMessage = str Unmask = bool Value = str +ValueKey = str +WithKey = str class AnomalyDetectorStatus(StrEnum): @@ -163,6 +192,16 @@ class ExportTaskStatusCode(StrEnum): RUNNING = "RUNNING" +class FlattenedElement(StrEnum): + first = "first" + last = "last" + + +class IndexSource(StrEnum): + ACCOUNT = "ACCOUNT" + LOG_GROUP = "LOG_GROUP" + + class InheritedProperty(StrEnum): ACCOUNT_DATA_PROTECTION = "ACCOUNT_DATA_PROTECTION" @@ -188,6 +227,8 @@ class OutputFormat(StrEnum): class PolicyType(StrEnum): DATA_PROTECTION_POLICY = "DATA_PROTECTION_POLICY" SUBSCRIPTION_FILTER_POLICY = "SUBSCRIPTION_FILTER_POLICY" + FIELD_INDEX_POLICY = "FIELD_INDEX_POLICY" + TRANSFORMER_POLICY = "TRANSFORMER_POLICY" class QueryStatus(StrEnum): @@ -256,6 +297,13 @@ class SuppressionUnit(StrEnum): HOURS = "HOURS" +class Type(StrEnum): + boolean = "boolean" + integer = "integer" + double = "double" + string = "string" + + class AccessDeniedException(ServiceException): code: str = "AccessDeniedException" sender_fault: bool = False @@ -399,6 +447,21 @@ class AccountPolicy(TypedDict, total=False): AccountPolicies = List[AccountPolicy] + + +class AddKeyEntry(TypedDict, total=False): + key: Key + value: AddKeyValue + overwriteIfExists: Optional[OverwriteIfExists] + + +AddKeyEntries = List[AddKeyEntry] + + +class AddKeys(TypedDict, total=False): + entries: AddKeyEntries + + AllowedFieldDelimiters = List[FieldDelimiter] @@ -483,6 +546,16 @@ class AssociateKmsKeyRequest(ServiceRequest): resourceIdentifier: Optional[ResourceIdentifier] +Columns = List[Column] + + +class CSV(TypedDict, total=False): + quoteCharacter: Optional[QuoteCharacter] + delimiter: Optional[Delimiter] + columns: Optional[Columns] + source: Optional[Source] + + class CancelExportTaskRequest(ServiceRequest): taskId: ExportTaskId @@ -518,6 +591,21 @@ class ConfigurationTemplate(TypedDict, total=False): ConfigurationTemplates = List[ConfigurationTemplate] + + +class CopyValueEntry(TypedDict, total=False): + source: Source + target: Target + overwriteIfExists: Optional[OverwriteIfExists] + + +CopyValueEntries = List[CopyValueEntry] + + +class CopyValue(TypedDict, total=False): + entries: CopyValueEntries + + Tags = Dict[TagKey, TagValue] @@ -591,6 +679,19 @@ class CreateLogStreamRequest(ServiceRequest): logStreamName: LogStreamName +MatchPatterns = List[MatchPattern] + + +class DateTimeConverter(TypedDict, total=False): + source: Source + target: Target + targetFormat: Optional[TargetFormat] + matchPatterns: MatchPatterns + sourceTimezone: Optional[SourceTimezone] + targetTimezone: Optional[TargetTimezone] + locale: Optional[Locale] + + class DeleteAccountPolicyRequest(ServiceRequest): policyName: PolicyName policyType: PolicyType @@ -620,6 +721,21 @@ class DeleteDestinationRequest(ServiceRequest): destinationName: DestinationName +class DeleteIndexPolicyRequest(ServiceRequest): + logGroupIdentifier: LogGroupIdentifier + + +class DeleteIndexPolicyResponse(TypedDict, total=False): + pass + + +DeleteWithKeys = List[WithKey] + + +class DeleteKeys(TypedDict, total=False): + withKeys: DeleteWithKeys + + class DeleteLogAnomalyDetectorRequest(ServiceRequest): anomalyDetectorArn: AnomalyDetectorArn @@ -659,6 +775,10 @@ class DeleteSubscriptionFilterRequest(ServiceRequest): filterName: FilterName +class DeleteTransformerRequest(ServiceRequest): + logGroupIdentifier: LogGroupIdentifier + + Deliveries = List[Delivery] @@ -696,10 +816,12 @@ class DescribeAccountPoliciesRequest(ServiceRequest): policyType: PolicyType policyName: Optional[PolicyName] accountIdentifiers: Optional[AccountIds] + nextToken: Optional[NextToken] class DescribeAccountPoliciesResponse(TypedDict, total=False): accountPolicies: Optional[AccountPolicies] + nextToken: Optional[NextToken] ResourceTypes = List[ResourceType] @@ -813,6 +935,54 @@ class DescribeExportTasksResponse(TypedDict, total=False): nextToken: Optional[NextToken] +DescribeFieldIndexesLogGroupIdentifiers = List[LogGroupIdentifier] + + +class DescribeFieldIndexesRequest(ServiceRequest): + logGroupIdentifiers: DescribeFieldIndexesLogGroupIdentifiers + nextToken: Optional[NextToken] + + +class FieldIndex(TypedDict, total=False): + logGroupIdentifier: Optional[LogGroupIdentifier] + fieldIndexName: Optional[FieldIndexName] + lastScanTime: Optional[Timestamp] + firstEventTime: Optional[Timestamp] + lastEventTime: Optional[Timestamp] + + +FieldIndexes = List[FieldIndex] + + +class DescribeFieldIndexesResponse(TypedDict, total=False): + fieldIndexes: Optional[FieldIndexes] + nextToken: Optional[NextToken] + + +DescribeIndexPoliciesLogGroupIdentifiers = List[LogGroupIdentifier] + + +class DescribeIndexPoliciesRequest(ServiceRequest): + logGroupIdentifiers: DescribeIndexPoliciesLogGroupIdentifiers + nextToken: Optional[NextToken] + + +class IndexPolicy(TypedDict, total=False): + logGroupIdentifier: Optional[LogGroupIdentifier] + lastUpdateTime: Optional[Timestamp] + policyDocument: Optional[PolicyDocument] + policyName: Optional[PolicyName] + source: Optional[IndexSource] + + +IndexPolicies = List[IndexPolicy] + + +class DescribeIndexPoliciesResponse(TypedDict, total=False): + indexPolicies: Optional[IndexPolicies] + nextToken: Optional[NextToken] + + class DescribeLogGroupsRequest(ServiceRequest): accountIdentifiers: Optional[AccountIds] logGroupNamePrefix: Optional[LogGroupName] @@ -908,6 +1078,7 @@ class MetricFilter(TypedDict, total=False): metricTransformations: Optional[MetricTransformations] creationTime: Optional[Timestamp] logGroupName: Optional[LogGroupName] + applyOnTransformedLogs: Optional[ApplyOnTransformedLogs] MetricFilters = List[MetricFilter] @@ -999,6 +1170,7 @@ class SubscriptionFilter(TypedDict, total=False): destinationArn: Optional[DestinationArn] roleArn: Optional[RoleArn] distribution: Optional[Distribution] + applyOnTransformedLogs: Optional[ApplyOnTransformedLogs] creationTime: Optional[Timestamp] @@ -1194,7 +1366,10 @@ class GetQueryResultsRequest(ServiceRequest): class QueryStatistics(TypedDict, total=False): recordsMatched: Optional[StatsValue] recordsScanned: Optional[StatsValue] + estimatedRecordsSkipped: Optional[StatsValue] bytesScanned: Optional[StatsValue] + estimatedBytesSkipped: Optional[StatsValue] + logGroupsScanned: Optional[StatsValue] class ResultField(TypedDict, total=False): @@ -1213,6 +1388,184 @@ class GetQueryResultsResponse(TypedDict, total=False): encryptionKey: Optional[EncryptionKey] +class GetTransformerRequest(ServiceRequest): + logGroupIdentifier: LogGroupIdentifier + + +UpperCaseStringWithKeys = List[WithKey] + + +class UpperCaseString(TypedDict, total=False): + withKeys: UpperCaseStringWithKeys + + +TypeConverterEntry = TypedDict( + "TypeConverterEntry", + { + "key": Key, + "type": Type, + }, + total=False, +) +TypeConverterEntries = List[TypeConverterEntry] + + +class TypeConverter(TypedDict, total=False): + entries: TypeConverterEntries + + +TrimStringWithKeys = List[WithKey] + + +class TrimString(TypedDict, total=False): + withKeys: TrimStringWithKeys + + +SubstituteStringEntry = TypedDict( + "SubstituteStringEntry", + { + "source": Source, + "from": FromKey, + "to": ToKey, + }, + total=False, +) +SubstituteStringEntries = List[SubstituteStringEntry] + + +class SubstituteString(TypedDict, total=False): + entries: SubstituteStringEntries + + +class SplitStringEntry(TypedDict, total=False): + source: Source + delimiter: Delimiter + + +SplitStringEntries = List[SplitStringEntry] + + +class SplitString(TypedDict, total=False): + entries: SplitStringEntries + + +class RenameKeyEntry(TypedDict, total=False): + key: Key + renameTo: RenameTo + overwriteIfExists: Optional[OverwriteIfExists] + + +RenameKeyEntries = List[RenameKeyEntry] + + +class RenameKeys(TypedDict, total=False): + entries: RenameKeyEntries + + +class ParseWAF(TypedDict, total=False): + source: Optional[Source] + + +class ParseVPC(TypedDict, total=False): + source: Optional[Source] + + +class ParsePostgres(TypedDict, total=False): + source: Optional[Source] + + +class ParseRoute53(TypedDict, total=False): + source: Optional[Source] + + +class ParseKeyValue(TypedDict, total=False): + source: Optional[Source] + destination: Optional[DestinationField] + fieldDelimiter: Optional[ParserFieldDelimiter] + keyValueDelimiter: Optional[KeyValueDelimiter] + keyPrefix: Optional[KeyPrefix] + nonMatchValue: Optional[NonMatchValue] + overwriteIfExists: Optional[OverwriteIfExists] + + +class ParseJSON(TypedDict, total=False): + source: Optional[Source] + destination: Optional[DestinationField] + + +class ParseCloudfront(TypedDict, total=False): + source: Optional[Source] + + +class MoveKeyEntry(TypedDict, total=False): + source: Source + target: Target + overwriteIfExists: Optional[OverwriteIfExists] + + +MoveKeyEntries = List[MoveKeyEntry] + + +class MoveKeys(TypedDict, total=False): + entries: MoveKeyEntries + + +LowerCaseStringWithKeys = List[WithKey] + + +class LowerCaseString(TypedDict, total=False): + withKeys: LowerCaseStringWithKeys + + +class ListToMap(TypedDict, total=False): + source: Source + key: Key + valueKey: Optional[ValueKey] + target: Optional[Target] + flatten: Optional[Flatten] + flattenedElement: Optional[FlattenedElement] + + +class Grok(TypedDict, total=False): + source: Optional[Source] + match: GrokMatch + + +class Processor(TypedDict, total=False): + addKeys: Optional[AddKeys] + copyValue: Optional[CopyValue] + csv: Optional[CSV] + dateTimeConverter: Optional[DateTimeConverter] + deleteKeys: Optional[DeleteKeys] + grok: Optional[Grok] + listToMap: Optional[ListToMap] + lowerCaseString: Optional[LowerCaseString] + moveKeys: Optional[MoveKeys] + parseCloudfront: Optional[ParseCloudfront] + parseJSON: Optional[ParseJSON] + parseKeyValue: Optional[ParseKeyValue] + parseRoute53: Optional[ParseRoute53] + parsePostgres: Optional[ParsePostgres] + parseVPC: Optional[ParseVPC] + parseWAF: Optional[ParseWAF] + renameKeys: Optional[RenameKeys] + splitString: Optional[SplitString] + substituteString: Optional[SubstituteString] + trimString: Optional[TrimString] + typeConverter: Optional[TypeConverter] + upperCaseString: Optional[UpperCaseString] + + +Processors = List[Processor] + + +class GetTransformerResponse(TypedDict, total=False): + logGroupIdentifier: Optional[LogGroupIdentifier] + creationTime: Optional[Timestamp] + lastModifiedTime: Optional[Timestamp] + transformerConfig: Optional[Processors] + + class InputLogEvent(TypedDict, total=False): timestamp: Timestamp message: EventMessage @@ -1244,6 +1597,20 @@ class ListLogAnomalyDetectorsResponse(TypedDict, total=False): nextToken: Optional[NextToken] +class ListLogGroupsForQueryRequest(ServiceRequest): + queryId: QueryId + nextToken: Optional[NextToken] + maxResults: Optional[ListLogGroupsForQueryMaxResults] + + +LogGroupIdentifiers = List[LogGroupIdentifier] + + +class ListLogGroupsForQueryResponse(TypedDict, total=False): + logGroupIdentifiers: Optional[LogGroupIdentifiers] + nextToken: Optional[NextToken] + + class ListTagsForResourceRequest(ServiceRequest): resourceArn: AmazonResourceName @@ -1290,9 +1657,6 @@ class LiveTailSessionUpdate(TypedDict, total=False): sessionResults: Optional[LiveTailSessionResults] -LogGroupIdentifiers = List[LogGroupIdentifier] - - class MetricFilterMatchRecord(TypedDict, total=False): eventNumber: Optional[EventNumber] eventMessage: Optional[EventMessage] @@ -1373,6 +1737,15 @@ class PutDestinationResponse(TypedDict, total=False): destination: Optional[Destination] +class PutIndexPolicyRequest(ServiceRequest): + logGroupIdentifier: LogGroupIdentifier + policyDocument: PolicyDocument + + +class PutIndexPolicyResponse(TypedDict, total=False): + indexPolicy: Optional[IndexPolicy] + + class PutLogEventsRequest(ServiceRequest): logGroupName: LogGroupName logStreamName: LogStreamName @@ -1402,6 +1775,7 @@ class PutMetricFilterRequest(ServiceRequest): filterName: FilterName filterPattern: FilterPattern metricTransformations: MetricTransformations + applyOnTransformedLogs: Optional[ApplyOnTransformedLogs] class PutQueryDefinitionRequest(ServiceRequest): @@ -1437,6 +1811,12 @@ class PutSubscriptionFilterRequest(ServiceRequest): destinationArn: DestinationArn roleArn: Optional[RoleArn] distribution: Optional[Distribution] + applyOnTransformedLogs: Optional[ApplyOnTransformedLogs] + + +class PutTransformerRequest(ServiceRequest): + logGroupIdentifier: LogGroupIdentifier + transformerConfig: Processors class StartLiveTailRequest(ServiceRequest): @@ -1510,6 +1890,24 @@ class TestMetricFilterResponse(TypedDict, total=False): matches: Optional[MetricFilterMatches] +class TestTransformerRequest(ServiceRequest): + transformerConfig: Processors + logEventMessages: TestEventMessages + + +class TransformedLogRecord(TypedDict, total=False): + eventNumber: Optional[EventNumber] + eventMessage: Optional[EventMessage] + transformedEventMessage: Optional[TransformedEventMessage] + + +TransformedLogs = List[TransformedLogRecord] + + +class TestTransformerResponse(TypedDict, total=False): + transformedLogs: Optional[TransformedLogs] + + class UntagLogGroupRequest(ServiceRequest): logGroupName: LogGroupName tags: TagList @@ -1664,6 +2062,12 @@ def delete_destination( ) -> None: raise NotImplementedError + @handler("DeleteIndexPolicy") + def delete_index_policy( + self, context: RequestContext, log_group_identifier: LogGroupIdentifier, **kwargs + ) -> DeleteIndexPolicyResponse: + raise NotImplementedError + @handler("DeleteLogAnomalyDetector") def delete_log_anomaly_detector( self, context: RequestContext, anomaly_detector_arn: AnomalyDetectorArn, **kwargs @@ -1724,6 +2128,12 @@ def delete_subscription_filter( ) -> None: raise NotImplementedError + @handler("DeleteTransformer") + def delete_transformer( + self, context: RequestContext, log_group_identifier: LogGroupIdentifier, **kwargs + ) -> None: + raise NotImplementedError + @handler("DescribeAccountPolicies") def describe_account_policies( self, @@ -1731,6 +2141,7 @@ def describe_account_policies( policy_type: PolicyType, policy_name: PolicyName = None, account_identifiers: AccountIds = None, + next_token: NextToken = None, **kwargs, ) -> DescribeAccountPoliciesResponse: raise NotImplementedError @@ -1802,6 +2213,26 @@ def describe_export_tasks( ) -> DescribeExportTasksResponse: raise NotImplementedError + @handler("DescribeFieldIndexes") + def describe_field_indexes( + self, + context: RequestContext, + log_group_identifiers: DescribeFieldIndexesLogGroupIdentifiers, + next_token: NextToken = None, + **kwargs, + ) -> DescribeFieldIndexesResponse: + raise NotImplementedError + + @handler("DescribeIndexPolicies") + def describe_index_policies( + self, + context: RequestContext, + log_group_identifiers: DescribeIndexPoliciesLogGroupIdentifiers, + next_token: NextToken = None, + **kwargs, + ) -> DescribeIndexPoliciesResponse: + raise NotImplementedError + @handler("DescribeLogGroups") def describe_log_groups( self, @@ -2000,6 +2431,12 @@ def get_query_results( ) -> GetQueryResultsResponse: raise NotImplementedError + @handler("GetTransformer") + def get_transformer( + self, context: RequestContext, log_group_identifier: LogGroupIdentifier, **kwargs + ) -> GetTransformerResponse: + raise NotImplementedError + @handler("ListAnomalies") def list_anomalies( self, @@ -2023,6 +2460,17 @@ def list_log_anomaly_detectors( ) -> ListLogAnomalyDetectorsResponse: raise NotImplementedError + @handler("ListLogGroupsForQuery") + def list_log_groups_for_query( + self, + context: RequestContext, + query_id: QueryId, + next_token: NextToken = None, + max_results: ListLogGroupsForQueryMaxResults = None, + **kwargs, + ) -> ListLogGroupsForQueryResponse: + raise NotImplementedError + @handler("ListTagsForResource") def list_tags_for_resource( self, context: RequestContext, resource_arn: AmazonResourceName, **kwargs @@ -2115,6 +2563,16 @@ def put_destination_policy( ) -> None: raise NotImplementedError + @handler("PutIndexPolicy") + def put_index_policy( + self, + context: RequestContext, + log_group_identifier: LogGroupIdentifier, + policy_document: PolicyDocument, + **kwargs, + ) -> PutIndexPolicyResponse: + raise NotImplementedError + @handler("PutLogEvents") def put_log_events( self, @@ -2136,6 +2594,7 @@ def put_metric_filter( filter_name: FilterName, filter_pattern: FilterPattern, metric_transformations: MetricTransformations, + apply_on_transformed_logs: ApplyOnTransformedLogs = None, **kwargs, ) -> None: raise NotImplementedError @@ -2183,6 +2642,17 @@ def put_subscription_filter( destination_arn: DestinationArn, role_arn: RoleArn = None, distribution: Distribution = None, + apply_on_transformed_logs: ApplyOnTransformedLogs = None, + **kwargs, + ) -> None: + raise NotImplementedError + + @handler("PutTransformer") + def put_transformer( + self, + context: RequestContext, + log_group_identifier: LogGroupIdentifier, + transformer_config: Processors, **kwargs, ) -> None: raise NotImplementedError @@ -2240,6 +2710,16 @@ def test_metric_filter( ) -> TestMetricFilterResponse: raise NotImplementedError + @handler("TestTransformer") + def test_transformer( + self, + context: RequestContext, + transformer_config: Processors, + log_event_messages: TestEventMessages, + **kwargs, + ) -> TestTransformerResponse: + raise NotImplementedError + @handler("UntagLogGroup") def untag_log_group( self, context: RequestContext, log_group_name: LogGroupName, tags: TagList, **kwargs diff --git a/localstack-core/localstack/aws/api/s3/__init__.py b/localstack-core/localstack/aws/api/s3/__init__.py index 3a7cdafe351b4..92e990daf1ce3 100644 --- a/localstack-core/localstack/aws/api/s3/__init__.py +++ b/localstack-core/localstack/aws/api/s3/__init__.py @@ -627,6 +627,12 @@ class BucketAlreadyOwnedByYou(ServiceException): BucketName: Optional[BucketName] +class EncryptionTypeMismatch(ServiceException): + code: str = "EncryptionTypeMismatch" + sender_fault: bool = False + status_code: int = 400 + + class InvalidObjectState(ServiceException): code: str = "InvalidObjectState" sender_fault: bool = False @@ -635,6 +641,18 @@ class InvalidObjectState(ServiceException): AccessTier: Optional[IntelligentTieringAccessTier] +class InvalidRequest(ServiceException): + code: str = "InvalidRequest" + sender_fault: bool = False + status_code: int = 400 + + +class InvalidWriteOffset(ServiceException): + code: str = "InvalidWriteOffset" + sender_fault: bool = False + status_code: int = 400 + + class NoSuchBucket(ServiceException): code: str = "NoSuchBucket" sender_fault: bool = False @@ -670,6 +688,12 @@ class ObjectNotInActiveTierError(ServiceException): status_code: int = 403 +class TooManyParts(ServiceException): + code: str = "TooManyParts" + sender_fault: bool = False + status_code: int = 400 + + class NoSuchLifecycleConfiguration(ServiceException): code: str = "NoSuchLifecycleConfiguration" sender_fault: bool = False @@ -993,12 +1017,16 @@ class AbortMultipartUploadOutput(TypedDict, total=False): RequestCharged: Optional[RequestCharged] +IfMatchInitiatedTime = datetime + + class AbortMultipartUploadRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey UploadId: MultipartUploadId RequestPayer: Optional[RequestPayer] ExpectedBucketOwner: Optional[AccountId] + IfMatchInitiatedTime: Optional[IfMatchInitiatedTime] class AccelerateConfiguration(TypedDict, total=False): @@ -1523,9 +1551,16 @@ class DefaultRetention(TypedDict, total=False): Years: Optional[Years] +Size = int +LastModifiedTime = datetime + + class ObjectIdentifier(TypedDict, total=False): Key: ObjectKey VersionId: Optional[ObjectVersionId] + ETag: Optional[ETag] + LastModifiedTime: Optional[LastModifiedTime] + Size: Optional[Size] ObjectIdentifierList = List[ObjectIdentifier] @@ -1625,6 +1660,10 @@ class DeleteObjectOutput(TypedDict, total=False): RequestCharged: Optional[RequestCharged] +IfMatchSize = int +IfMatchLastModifiedTime = datetime + + class DeleteObjectRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey @@ -1633,6 +1672,9 @@ class DeleteObjectRequest(ServiceRequest): RequestPayer: Optional[RequestPayer] BypassGovernanceRetention: Optional[BypassGovernanceRetention] ExpectedBucketOwner: Optional[AccountId] + IfMatch: Optional[IfMatch] + IfMatchLastModifiedTime: Optional[IfMatchLastModifiedTime] + IfMatchSize: Optional[IfMatchSize] class DeleteObjectTaggingOutput(TypedDict, total=False): @@ -2163,9 +2205,6 @@ class GetObjectAclRequest(ServiceRequest): ExpectedBucketOwner: Optional[AccountId] -Size = int - - class ObjectPart(TypedDict, total=False): PartNumber: Optional[PartNumber] Size: Optional[Size] @@ -3133,9 +3172,13 @@ class PutObjectOutput(TypedDict, total=False): SSEKMSKeyId: Optional[SSEKMSKeyId] SSEKMSEncryptionContext: Optional[SSEKMSEncryptionContext] BucketKeyEnabled: Optional[BucketKeyEnabled] + Size: Optional[Size] RequestCharged: Optional[RequestCharged] +WriteOffsetBytes = int + + class PutObjectRequest(ServiceRequest): Body: Optional[IO[Body]] ACL: Optional[ObjectCannedACL] @@ -3159,6 +3202,7 @@ class PutObjectRequest(ServiceRequest): GrantReadACP: Optional[GrantReadACP] GrantWriteACP: Optional[GrantWriteACP] Key: ObjectKey + WriteOffsetBytes: Optional[WriteOffsetBytes] Metadata: Optional[Metadata] ServerSideEncryption: Optional[ServerSideEncryption] StorageClass: Optional[StorageClass] @@ -3453,6 +3497,7 @@ def abort_multipart_upload( upload_id: MultipartUploadId, request_payer: RequestPayer = None, expected_bucket_owner: AccountId = None, + if_match_initiated_time: IfMatchInitiatedTime = None, **kwargs, ) -> AbortMultipartUploadOutput: raise NotImplementedError @@ -3738,6 +3783,9 @@ def delete_object( request_payer: RequestPayer = None, bypass_governance_retention: BypassGovernanceRetention = None, expected_bucket_owner: AccountId = None, + if_match: IfMatch = None, + if_match_last_modified_time: IfMatchLastModifiedTime = None, + if_match_size: IfMatchSize = None, **kwargs, ) -> DeleteObjectOutput: raise NotImplementedError @@ -4611,6 +4659,7 @@ def put_object( grant_read: GrantRead = None, grant_read_acp: GrantReadACP = None, grant_write_acp: GrantWriteACP = None, + write_offset_bytes: WriteOffsetBytes = None, metadata: Metadata = None, server_side_encryption: ServerSideEncryption = None, storage_class: StorageClass = None, diff --git a/localstack-core/localstack/aws/api/ses/__init__.py b/localstack-core/localstack/aws/api/ses/__init__.py index 525613eb92783..f4c9960eb25cf 100644 --- a/localstack-core/localstack/aws/api/ses/__init__.py +++ b/localstack-core/localstack/aws/api/ses/__init__.py @@ -12,6 +12,7 @@ Charset = str Cidr = str ConfigurationSetName = str +ConnectInstanceArn = str CustomRedirectDomain = str DefaultDimensionValue = str DiagnosticCode = str @@ -527,6 +528,13 @@ class ConfigurationSet(TypedDict, total=False): ConfigurationSetAttributeList = List[ConfigurationSetAttribute] ConfigurationSets = List[ConfigurationSet] + + +class ConnectAction(TypedDict, total=False): + InstanceARN: ConnectInstanceArn + IAMRoleARN: IAMRoleARN + + Counter = int @@ -645,6 +653,7 @@ class ReceiptAction(TypedDict, total=False): StopAction: Optional[StopAction] AddHeaderAction: Optional[AddHeaderAction] SNSAction: Optional[SNSAction] + ConnectAction: Optional[ConnectAction] ReceiptActionsList = List[ReceiptAction] diff --git a/localstack-core/localstack/aws/api/ssm/__init__.py b/localstack-core/localstack/aws/api/ssm/__init__.py index 88ca68847cd9a..a906bb4247944 100644 --- a/localstack-core/localstack/aws/api/ssm/__init__.py +++ b/localstack-core/localstack/aws/api/ssm/__init__.py @@ -10,6 +10,8 @@ ActivationDescription = str ActivationId = str AgentErrorCode = str +AgentType = str +AgentVersion = str AggregatorSchemaOnly = bool AlarmName = str AllowedPattern = str @@ -100,6 +102,7 @@ EffectiveInstanceAssociationMaxResults = int ErrorCount = int ExcludeAccount = str +ExecutionPreviewId = str ExecutionRoleName = str GetInventorySchemaMaxResults = int GetOpsMetadataMaxResults = int @@ -121,6 +124,7 @@ InstancePropertyStringFilterKey = str InstanceRole = str InstanceState = str +InstanceStatus = str InstanceTagName = str InstanceType = str InstancesCount = int @@ -140,6 +144,7 @@ InventoryResultItemKey = str InventoryTypeDisplayName = str InvocationTraceOutput = str +IpAddress = str IsSubTypeSchema = bool KeyName = str LastResourceDataSyncMessage = str @@ -185,6 +190,12 @@ MetadataKey = str MetadataValueString = str NextToken = str +NodeAccountId = str +NodeFilterValue = str +NodeId = str +NodeOrganizationalUnitId = str +NodeOrganizationalUnitPath = str +NodeRegion = str NotificationArn = str OpsAggregatorType = str OpsAggregatorValue = str @@ -627,6 +638,13 @@ class ExecutionMode(StrEnum): Interactive = "Interactive" +class ExecutionPreviewStatus(StrEnum): + Pending = "Pending" + InProgress = "InProgress" + Success = "Success" + Failed = "Failed" + + class ExternalAlarmState(StrEnum): UNKNOWN = "UNKNOWN" ALARM = "ALARM" @@ -638,6 +656,12 @@ class Fault(StrEnum): Unknown = "Unknown" +class ImpactType(StrEnum): + Mutating = "Mutating" + NonMutating = "NonMutating" + Undetermined = "Undetermined" + + class InstanceInformationFilterKey(StrEnum): InstanceIds = "InstanceIds" AgentVersion = "AgentVersion" @@ -734,6 +758,53 @@ class MaintenanceWindowTaskType(StrEnum): LAMBDA = "LAMBDA" +class ManagedStatus(StrEnum): + All = "All" + Managed = "Managed" + Unmanaged = "Unmanaged" + + +class NodeAggregatorType(StrEnum): + Count = "Count" + + +class NodeAttributeName(StrEnum): + AgentVersion = "AgentVersion" + PlatformName = "PlatformName" + PlatformType = "PlatformType" + PlatformVersion = "PlatformVersion" + Region = "Region" + ResourceType = "ResourceType" + + +class NodeFilterKey(StrEnum): + AgentType = "AgentType" + AgentVersion = "AgentVersion" + ComputerName = "ComputerName" + InstanceId = "InstanceId" + InstanceStatus = "InstanceStatus" + IpAddress = "IpAddress" + ManagedStatus = "ManagedStatus" + PlatformName = "PlatformName" + PlatformType = "PlatformType" + PlatformVersion = "PlatformVersion" + ResourceType = "ResourceType" + OrganizationalUnitId = "OrganizationalUnitId" + OrganizationalUnitPath = "OrganizationalUnitPath" + Region = "Region" + AccountId = "AccountId" + + +class NodeFilterOperatorType(StrEnum): + Equal = "Equal" + NotEqual = "NotEqual" + BeginWith = "BeginWith" + + +class NodeTypeName(StrEnum): + Instance = "Instance" + + class NotificationEvent(StrEnum): All = "All" InProgress = "InProgress" @@ -1856,6 +1927,12 @@ class UnsupportedOperatingSystem(ServiceException): status_code: int = 400 +class UnsupportedOperationException(ServiceException): + code: str = "UnsupportedOperationException" + sender_fault: bool = False + status_code: int = 400 + + class UnsupportedParameterType(ServiceException): code: str = "UnsupportedParameterType" sender_fault: bool = False @@ -1868,6 +1945,13 @@ class UnsupportedPlatformType(ServiceException): status_code: int = 400 +class ValidationException(ServiceException): + code: str = "ValidationException" + sender_fault: bool = False + status_code: int = 400 + ReasonCode: Optional[String] + + AccountIdList = List[AccountId] @@ -2312,6 +2396,15 @@ class AutomationExecutionFilter(TypedDict, total=False): AutomationExecutionFilterList = List[AutomationExecutionFilter] +class AutomationExecutionInputs(TypedDict, total=False): + Parameters: Optional[AutomationParameterMap] + TargetParameterName: Optional[AutomationParameterKey] + Targets: Optional[Targets] + TargetMaps: Optional[TargetMaps] + TargetLocations: Optional[TargetLocations] + TargetLocationsURL: Optional[TargetLocationsURL] + + class AutomationExecutionMetadata(TypedDict, total=False): AutomationExecutionId: Optional[AutomationExecutionId] DocumentName: Optional[DocumentName] @@ -2347,6 +2440,25 @@ class AutomationExecutionMetadata(TypedDict, total=False): AutomationExecutionMetadataList = List[AutomationExecutionMetadata] + + +class TargetPreview(TypedDict, total=False): + Count: Optional[Integer] + TargetType: Optional[String] + + +TargetPreviewList = List[TargetPreview] +RegionList = List[Region] +StepPreviewMap = Dict[ImpactType, Integer] + + +class AutomationExecutionPreview(TypedDict, total=False): + StepPreviews: Optional[StepPreviewMap] + Regions: Optional[RegionList] + TargetPreviews: Optional[TargetPreviewList] + TotalAccounts: Optional[Integer] + + PatchSourceProductList = List[PatchSourceProduct] @@ -4154,6 +4266,14 @@ class DocumentVersionInfo(TypedDict, total=False): DocumentVersionList = List[DocumentVersionInfo] +class ExecutionInputs(TypedDict, total=False): + Automation: Optional[AutomationExecutionInputs] + + +class ExecutionPreview(TypedDict, total=False): + Automation: Optional[AutomationExecutionPreview] + + class GetAutomationExecutionRequest(ServiceRequest): AutomationExecutionId: AutomationExecutionId @@ -4253,6 +4373,18 @@ class GetDocumentResult(TypedDict, total=False): ReviewStatus: Optional[ReviewStatus] +class GetExecutionPreviewRequest(ServiceRequest): + ExecutionPreviewId: ExecutionPreviewId + + +class GetExecutionPreviewResponse(TypedDict, total=False): + ExecutionPreviewId: Optional[ExecutionPreviewId] + EndedAt: Optional[DateTime] + Status: Optional[ExecutionPreviewStatus] + StatusMessage: Optional[String] + ExecutionPreview: Optional[ExecutionPreview] + + class ResultAttribute(TypedDict, total=False): TypeName: InventoryItemTypeName @@ -4764,6 +4896,19 @@ class GetServiceSettingResult(TypedDict, total=False): ServiceSetting: Optional[ServiceSetting] +class InstanceInfo(TypedDict, total=False): + AgentType: Optional[AgentType] + AgentVersion: Optional[AgentVersion] + ComputerName: Optional[ComputerName] + InstanceStatus: Optional[InstanceStatus] + IpAddress: Optional[IpAddress] + ManagedStatus: Optional[ManagedStatus] + PlatformType: Optional[PlatformType] + PlatformName: Optional[PlatformName] + PlatformVersion: Optional[PlatformVersion] + ResourceType: Optional[ResourceType] + + InventoryItemContentContext = Dict[AttributeName, AttributeValue] @@ -4924,6 +5069,81 @@ class ListInventoryEntriesResult(TypedDict, total=False): NextToken: Optional[NextToken] +NodeFilterValueList = List[NodeFilterValue] + + +class NodeFilter(TypedDict, total=False): + Key: NodeFilterKey + Values: NodeFilterValueList + Type: Optional[NodeFilterOperatorType] + + +NodeFilterList = List[NodeFilter] + + +class ListNodesRequest(ServiceRequest): + SyncName: Optional[ResourceDataSyncName] + Filters: Optional[NodeFilterList] + NextToken: Optional[NextToken] + MaxResults: Optional[MaxResults] + + +class NodeType(TypedDict, total=False): + Instance: Optional[InstanceInfo] + + +class NodeOwnerInfo(TypedDict, total=False): + AccountId: Optional[NodeAccountId] + OrganizationalUnitId: Optional[NodeOrganizationalUnitId] + OrganizationalUnitPath: Optional[NodeOrganizationalUnitPath] + + +NodeCaptureTime = datetime + + +class Node(TypedDict, total=False): + CaptureTime: Optional[NodeCaptureTime] + Id: Optional[NodeId] + Owner: Optional[NodeOwnerInfo] + Region: Optional[NodeRegion] + NodeType: Optional[NodeType] + + +NodeList = List[Node] + + +class ListNodesResult(TypedDict, total=False): + Nodes: Optional[NodeList] + NextToken: Optional[NextToken] + + +NodeAggregatorList = List["NodeAggregator"] + + +class NodeAggregator(TypedDict, total=False): + AggregatorType: NodeAggregatorType + TypeName: NodeTypeName + AttributeName: NodeAttributeName + Aggregators: Optional[NodeAggregatorList] + + +class ListNodesSummaryRequest(ServiceRequest): + SyncName: Optional[ResourceDataSyncName] + Filters: Optional[NodeFilterList] + Aggregators: NodeAggregatorList + NextToken: Optional[NextToken] + MaxResults: Optional[MaxResults] + + +NodeSummary = Dict[AttributeName, AttributeValue] +NodeSummaryList = List[NodeSummary] + + +class ListNodesSummaryResult(TypedDict, total=False): + Summary: Optional[NodeSummaryList] + NextToken: Optional[NextToken] + + OpsItemEventFilterValues = List[OpsItemEventFilterValue] @@ -5351,6 +5571,16 @@ class StartChangeRequestExecutionResult(TypedDict, total=False): AutomationExecutionId: Optional[AutomationExecutionId] +class StartExecutionPreviewRequest(ServiceRequest): + DocumentName: DocumentName + DocumentVersion: Optional[DocumentVersion] + ExecutionInputs: Optional[ExecutionInputs] + + +class StartExecutionPreviewResponse(TypedDict, total=False): + ExecutionPreviewId: Optional[ExecutionPreviewId] + + class StartSessionRequest(ServiceRequest): Target: SessionTarget DocumentName: Optional[DocumentARN] @@ -6430,6 +6660,12 @@ def get_document( ) -> GetDocumentResult: raise NotImplementedError + @handler("GetExecutionPreview") + def get_execution_preview( + self, context: RequestContext, execution_preview_id: ExecutionPreviewId, **kwargs + ) -> GetExecutionPreviewResponse: + raise NotImplementedError + @handler("GetInventory") def get_inventory( self, @@ -6746,6 +6982,31 @@ def list_inventory_entries( ) -> ListInventoryEntriesResult: raise NotImplementedError + @handler("ListNodes") + def list_nodes( + self, + context: RequestContext, + sync_name: ResourceDataSyncName = None, + filters: NodeFilterList = None, + next_token: NextToken = None, + max_results: MaxResults = None, + **kwargs, + ) -> ListNodesResult: + raise NotImplementedError + + @handler("ListNodesSummary") + def list_nodes_summary( + self, + context: RequestContext, + aggregators: NodeAggregatorList, + sync_name: ResourceDataSyncName = None, + filters: NodeFilterList = None, + next_token: NextToken = None, + max_results: MaxResults = None, + **kwargs, + ) -> ListNodesSummaryResult: + raise NotImplementedError + @handler("ListOpsItemEvents") def list_ops_item_events( self, @@ -7022,6 +7283,17 @@ def start_change_request_execution( ) -> StartChangeRequestExecutionResult: raise NotImplementedError + @handler("StartExecutionPreview") + def start_execution_preview( + self, + context: RequestContext, + document_name: DocumentName, + document_version: DocumentVersion = None, + execution_inputs: ExecutionInputs = None, + **kwargs, + ) -> StartExecutionPreviewResponse: + raise NotImplementedError + @handler("StartSession") def start_session( self, diff --git a/localstack-core/localstack/services/apigateway/legacy/provider.py b/localstack-core/localstack/services/apigateway/legacy/provider.py index b0b864c6b63de..1c0471d6ec209 100644 --- a/localstack-core/localstack/services/apigateway/legacy/provider.py +++ b/localstack-core/localstack/services/apigateway/legacy/provider.py @@ -73,6 +73,7 @@ RequestValidator, RequestValidators, Resource, + ResourceOwner, RestApi, RestApis, SecurityPolicy, @@ -409,6 +410,7 @@ def create_domain_name( security_policy: SecurityPolicy = None, mutual_tls_authentication: MutualTlsAuthenticationInput = None, ownership_verification_certificate_arn: String = None, + policy: String = None, **kwargs, ) -> DomainName: if not domain_name: @@ -444,7 +446,9 @@ def create_domain_name( return domain @handler("GetDomainName") - def get_domain_name(self, context: RequestContext, domain_name: String, **kwargs) -> DomainName: + def get_domain_name( + self, context: RequestContext, domain_name: String, domain_name_id: String = None, **kwargs + ) -> DomainName: store: ApiGatewayStore = get_apigateway_store(context=context) if domain := store.domain_names.get(domain_name): return domain @@ -456,6 +460,7 @@ def get_domain_names( context: RequestContext, position: String = None, limit: NullableInteger = None, + resource_owner: ResourceOwner = None, **kwargs, ) -> DomainNames: store = get_apigateway_store(context=context) @@ -463,7 +468,9 @@ def get_domain_names( return DomainNames(items=list(domain_names), position=position) @handler("DeleteDomainName") - def delete_domain_name(self, context: RequestContext, domain_name: String, **kwargs) -> None: + def delete_domain_name( + self, context: RequestContext, domain_name: String, domain_name_id: String = None, **kwargs + ) -> None: store: ApiGatewayStore = get_apigateway_store(context=context) if not store.domain_names.pop(domain_name, None): raise NotFoundException("Invalid domain name identifier specified") @@ -1448,6 +1455,7 @@ def get_base_path_mappings( self, context: RequestContext, domain_name: String, + domain_name_id: String = None, position: String = None, limit: NullableInteger = None, **kwargs, @@ -1462,7 +1470,12 @@ def get_base_path_mappings( return BasePathMappings(items=result) def get_base_path_mapping( - self, context: RequestContext, domain_name: String, base_path: String, **kwargs + self, + context: RequestContext, + domain_name: String, + base_path: String, + domain_name_id: String = None, + **kwargs, ) -> BasePathMapping: region_details = get_apigateway_store(context=context) @@ -1479,6 +1492,7 @@ def create_base_path_mapping( context: RequestContext, domain_name: String, rest_api_id: String, + domain_name_id: String = None, base_path: String = None, stage: String = None, **kwargs, @@ -1505,6 +1519,7 @@ def update_base_path_mapping( context: RequestContext, domain_name: String, base_path: String, + domain_name_id: String = None, patch_operations: ListOfPatchOperation = None, **kwargs, ) -> BasePathMapping: @@ -1533,7 +1548,12 @@ def update_base_path_mapping( return BasePathMapping(**result) def delete_base_path_mapping( - self, context: RequestContext, domain_name: String, base_path: String, **kwargs + self, + context: RequestContext, + domain_name: String, + base_path: String, + domain_name_id: String = None, + **kwargs, ) -> None: region_details = get_apigateway_store(context=context) diff --git a/localstack-core/localstack/services/s3/provider.py b/localstack-core/localstack/services/s3/provider.py index ad6cb80cfabd2..f8a25779ff1c1 100644 --- a/localstack-core/localstack/services/s3/provider.py +++ b/localstack-core/localstack/services/s3/provider.py @@ -99,6 +99,10 @@ HeadBucketOutput, HeadObjectOutput, HeadObjectRequest, + IfMatch, + IfMatchInitiatedTime, + IfMatchLastModifiedTime, + IfMatchSize, IfNoneMatch, IntelligentTieringConfiguration, IntelligentTieringId, @@ -1090,6 +1094,9 @@ def delete_object( request_payer: RequestPayer = None, bypass_governance_retention: BypassGovernanceRetention = None, expected_bucket_owner: AccountId = None, + if_match: IfMatch = None, + if_match_last_modified_time: IfMatchLastModifiedTime = None, + if_match_size: IfMatchSize = None, **kwargs, ) -> DeleteObjectOutput: store, s3_bucket = self._get_cross_account_bucket(context, bucket) @@ -2464,6 +2471,7 @@ def abort_multipart_upload( upload_id: MultipartUploadId, request_payer: RequestPayer = None, expected_bucket_owner: AccountId = None, + if_match_initiated_time: IfMatchInitiatedTime = None, **kwargs, ) -> AbortMultipartUploadOutput: store, s3_bucket = self._get_cross_account_bucket(context, bucket) diff --git a/pyproject.toml b/pyproject.toml index 91412d447e9b8..69b8abc37d5b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,9 +53,9 @@ Issues = "https://github.com/localstack/localstack/issues" # minimal required to actually run localstack on the host for services natively implemented in python base-runtime = [ # pinned / updated by ASF update action - "boto3==1.35.63", + "boto3==1.35.68", # pinned / updated by ASF update action - "botocore==1.35.63", + "botocore==1.35.68", "awscrt>=0.13.14", "cbor2>=5.2.0", "dnspython>=1.16.0", diff --git a/requirements-base-runtime.txt b/requirements-base-runtime.txt index feee722c37172..d7f6fb63b36bc 100644 --- a/requirements-base-runtime.txt +++ b/requirements-base-runtime.txt @@ -11,9 +11,9 @@ attrs==24.2.0 # referencing awscrt==0.23.0 # via localstack-core (pyproject.toml) -boto3==1.35.63 +boto3==1.35.68 # via localstack-core (pyproject.toml) -botocore==1.35.63 +botocore==1.35.68 # via # boto3 # localstack-core (pyproject.toml) diff --git a/requirements-dev.txt b/requirements-dev.txt index f09b99f9eb6cf..69a21b488f16c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -43,17 +43,17 @@ aws-sam-translator==1.92.0 # localstack-core aws-xray-sdk==2.14.0 # via moto-ext -awscli==1.36.4 +awscli==1.36.9 # via localstack-core awscrt==0.23.0 # via localstack-core -boto3==1.35.63 +boto3==1.35.68 # via # amazon-kclpy # aws-sam-translator # localstack-core # moto-ext -botocore==1.35.63 +botocore==1.35.68 # via # aws-xray-sdk # awscli diff --git a/requirements-runtime.txt b/requirements-runtime.txt index 396a18c3c3020..9bd3a3411b3e3 100644 --- a/requirements-runtime.txt +++ b/requirements-runtime.txt @@ -29,17 +29,17 @@ aws-sam-translator==1.92.0 # localstack-core (pyproject.toml) aws-xray-sdk==2.14.0 # via moto-ext -awscli==1.36.4 +awscli==1.36.9 # via localstack-core (pyproject.toml) awscrt==0.23.0 # via localstack-core -boto3==1.35.63 +boto3==1.35.68 # via # amazon-kclpy # aws-sam-translator # localstack-core # moto-ext -botocore==1.35.63 +botocore==1.35.68 # via # aws-xray-sdk # awscli diff --git a/requirements-test.txt b/requirements-test.txt index ac11ee705832c..d40d0a3449c8f 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -43,17 +43,17 @@ aws-sam-translator==1.92.0 # localstack-core aws-xray-sdk==2.14.0 # via moto-ext -awscli==1.36.4 +awscli==1.36.9 # via localstack-core awscrt==0.23.0 # via localstack-core -boto3==1.35.63 +boto3==1.35.68 # via # amazon-kclpy # aws-sam-translator # localstack-core # moto-ext -botocore==1.35.63 +botocore==1.35.68 # via # aws-xray-sdk # awscli diff --git a/requirements-typehint.txt b/requirements-typehint.txt index 56b8a5351c855..59724b7a588f9 100644 --- a/requirements-typehint.txt +++ b/requirements-typehint.txt @@ -43,11 +43,11 @@ aws-sam-translator==1.92.0 # localstack-core aws-xray-sdk==2.14.0 # via moto-ext -awscli==1.36.4 +awscli==1.36.9 # via localstack-core awscrt==0.23.0 # via localstack-core -boto3==1.35.63 +boto3==1.35.68 # via # amazon-kclpy # aws-sam-translator @@ -55,7 +55,7 @@ boto3==1.35.63 # moto-ext boto3-stubs==1.35.64 # via localstack-core (pyproject.toml) -botocore==1.35.63 +botocore==1.35.68 # via # aws-xray-sdk # awscli From 3a32d7628ec1ce606abba8d79701c466fc6ad5e7 Mon Sep 17 00:00:00 2001 From: LocalStack Bot <88328844+localstack-bot@users.noreply.github.com> Date: Tue, 26 Nov 2024 08:08:18 +0100 Subject: [PATCH 06/38] Upgrade pinned Python dependencies (#11926) Co-authored-by: LocalStack Bot --- .pre-commit-config.yaml | 2 +- requirements-base-runtime.txt | 4 +- requirements-dev.txt | 28 +++++------ requirements-runtime.txt | 14 +++--- requirements-test.txt | 22 ++++----- requirements-typehint.txt | 92 +++++++++++++++++------------------ 6 files changed, 81 insertions(+), 81 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f2d3823ebc122..70b7c5de26c66 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.7.4 + rev: v0.8.0 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/requirements-base-runtime.txt b/requirements-base-runtime.txt index d7f6fb63b36bc..b20d607bee59d 100644 --- a/requirements-base-runtime.txt +++ b/requirements-base-runtime.txt @@ -9,7 +9,7 @@ attrs==24.2.0 # jsonschema # localstack-twisted # referencing -awscrt==0.23.0 +awscrt==0.23.1 # via localstack-core (pyproject.toml) boto3==1.35.68 # via localstack-core (pyproject.toml) @@ -170,7 +170,7 @@ rpds-py==0.21.0 # via # jsonschema # referencing -s3transfer==0.10.3 +s3transfer==0.10.4 # via boto3 semver==3.0.2 # via localstack-core (pyproject.toml) diff --git a/requirements-dev.txt b/requirements-dev.txt index 69a21b488f16c..6e0f93a244d3a 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -27,7 +27,7 @@ attrs==24.2.0 # jsonschema # localstack-twisted # referencing -aws-cdk-asset-awscli-v1==2.2.212 +aws-cdk-asset-awscli-v1==2.2.213 # via aws-cdk-lib aws-cdk-asset-kubectl-v20==2.1.3 # via aws-cdk-lib @@ -35,9 +35,9 @@ aws-cdk-asset-node-proxy-agent-v6==2.1.0 # via aws-cdk-lib aws-cdk-cloud-assembly-schema==38.0.1 # via aws-cdk-lib -aws-cdk-lib==2.167.1 +aws-cdk-lib==2.171.0 # via localstack-core -aws-sam-translator==1.92.0 +aws-sam-translator==1.94.0 # via # cfn-lint # localstack-core @@ -45,7 +45,7 @@ aws-xray-sdk==2.14.0 # via moto-ext awscli==1.36.9 # via localstack-core -awscrt==0.23.0 +awscrt==0.23.1 # via localstack-core boto3==1.35.68 # via @@ -99,7 +99,7 @@ constantly==23.10.4 # via localstack-twisted constructs==10.4.2 # via aws-cdk-lib -coverage==7.6.7 +coverage==7.6.8 # via # coveralls # localstack-core @@ -173,7 +173,7 @@ hyperframe==6.0.1 # via h2 hyperlink==21.0.0 # via localstack-twisted -identify==2.6.2 +identify==2.6.3 # via pre-commit idna==3.10 # via @@ -198,7 +198,7 @@ jmespath==1.0.1 # botocore joserfc==1.0.0 # via moto-ext -jpype1-ext==0.0.1 +jpype1-ext==0.0.2 # via localstack-core jsii==1.105.0 # via @@ -338,9 +338,9 @@ pyasn1==0.6.1 # via rsa pycparser==2.22 # via cffi -pydantic==2.9.2 +pydantic==2.10.1 # via aws-sam-translator -pydantic-core==2.23.4 +pydantic-core==2.27.1 # via pydantic pygments==2.18.0 # via rich @@ -364,7 +364,7 @@ pytest==8.3.3 # pytest-tinybird pytest-httpserver==1.1.0 # via localstack-core -pytest-rerunfailures==14.0 +pytest-rerunfailures==15.0 # via localstack-core pytest-split==0.10.0 # via localstack-core @@ -433,9 +433,9 @@ rsa==4.7.2 # via awscli rstr==3.2.2 # via localstack-core (pyproject.toml) -ruff==0.7.4 +ruff==0.8.0 # via localstack-core (pyproject.toml) -s3transfer==0.10.3 +s3transfer==0.10.4 # via # awscli # boto3 @@ -485,7 +485,7 @@ urllib3==2.2.3 # opensearch-py # requests # responses -virtualenv==20.27.1 +virtualenv==20.28.0 # via pre-commit websocket-client==1.8.0 # via localstack-core @@ -496,7 +496,7 @@ werkzeug==3.1.3 # openapi-core # pytest-httpserver # rolo -wrapt==1.16.0 +wrapt==1.17.0 # via aws-xray-sdk wsproto==1.2.0 # via hypercorn diff --git a/requirements-runtime.txt b/requirements-runtime.txt index 9bd3a3411b3e3..9a0ffb8826e1c 100644 --- a/requirements-runtime.txt +++ b/requirements-runtime.txt @@ -23,7 +23,7 @@ attrs==24.2.0 # jsonschema # localstack-twisted # referencing -aws-sam-translator==1.92.0 +aws-sam-translator==1.94.0 # via # cfn-lint # localstack-core (pyproject.toml) @@ -31,7 +31,7 @@ aws-xray-sdk==2.14.0 # via moto-ext awscli==1.36.9 # via localstack-core (pyproject.toml) -awscrt==0.23.0 +awscrt==0.23.1 # via localstack-core boto3==1.35.68 # via @@ -143,7 +143,7 @@ jmespath==1.0.1 # botocore joserfc==1.0.0 # via moto-ext -jpype1-ext==0.0.1 +jpype1-ext==0.0.2 # via localstack-core (pyproject.toml) json5==0.9.28 # via localstack-core (pyproject.toml) @@ -241,9 +241,9 @@ pyasn1==0.6.1 # via rsa pycparser==2.22 # via cffi -pydantic==2.9.2 +pydantic==2.10.1 # via aws-sam-translator -pydantic-core==2.23.4 +pydantic-core==2.27.1 # via pydantic pygments==2.18.0 # via rich @@ -315,7 +315,7 @@ rpds-py==0.21.0 # referencing rsa==4.7.2 # via awscli -s3transfer==0.10.3 +s3transfer==0.10.4 # via # awscli # boto3 @@ -357,7 +357,7 @@ werkzeug==3.1.3 # moto-ext # openapi-core # rolo -wrapt==1.16.0 +wrapt==1.17.0 # via aws-xray-sdk wsproto==1.2.0 # via hypercorn diff --git a/requirements-test.txt b/requirements-test.txt index d40d0a3449c8f..a2d621b7c0a8f 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -27,7 +27,7 @@ attrs==24.2.0 # jsonschema # localstack-twisted # referencing -aws-cdk-asset-awscli-v1==2.2.212 +aws-cdk-asset-awscli-v1==2.2.213 # via aws-cdk-lib aws-cdk-asset-kubectl-v20==2.1.3 # via aws-cdk-lib @@ -35,9 +35,9 @@ aws-cdk-asset-node-proxy-agent-v6==2.1.0 # via aws-cdk-lib aws-cdk-cloud-assembly-schema==38.0.1 # via aws-cdk-lib -aws-cdk-lib==2.167.1 +aws-cdk-lib==2.171.0 # via localstack-core (pyproject.toml) -aws-sam-translator==1.92.0 +aws-sam-translator==1.94.0 # via # cfn-lint # localstack-core @@ -45,7 +45,7 @@ aws-xray-sdk==2.14.0 # via moto-ext awscli==1.36.9 # via localstack-core -awscrt==0.23.0 +awscrt==0.23.1 # via localstack-core boto3==1.35.68 # via @@ -97,7 +97,7 @@ constantly==23.10.4 # via localstack-twisted constructs==10.4.2 # via aws-cdk-lib -coverage==7.6.7 +coverage==7.6.8 # via localstack-core (pyproject.toml) crontab==1.0.1 # via localstack-core @@ -182,7 +182,7 @@ jmespath==1.0.1 # botocore joserfc==1.0.0 # via moto-ext -jpype1-ext==0.0.1 +jpype1-ext==0.0.2 # via localstack-core jsii==1.105.0 # via @@ -308,9 +308,9 @@ pyasn1==0.6.1 # via rsa pycparser==2.22 # via cffi -pydantic==2.9.2 +pydantic==2.10.1 # via aws-sam-translator -pydantic-core==2.23.4 +pydantic-core==2.27.1 # via pydantic pygments==2.18.0 # via rich @@ -332,7 +332,7 @@ pytest==8.3.3 # pytest-tinybird pytest-httpserver==1.1.0 # via localstack-core (pyproject.toml) -pytest-rerunfailures==14.0 +pytest-rerunfailures==15.0 # via localstack-core (pyproject.toml) pytest-split==0.10.0 # via localstack-core (pyproject.toml) @@ -397,7 +397,7 @@ rpds-py==0.21.0 # referencing rsa==4.7.2 # via awscli -s3transfer==0.10.3 +s3transfer==0.10.4 # via # awscli # boto3 @@ -456,7 +456,7 @@ werkzeug==3.1.3 # openapi-core # pytest-httpserver # rolo -wrapt==1.16.0 +wrapt==1.17.0 # via aws-xray-sdk wsproto==1.2.0 # via hypercorn diff --git a/requirements-typehint.txt b/requirements-typehint.txt index 59724b7a588f9..0c51d6db60ef0 100644 --- a/requirements-typehint.txt +++ b/requirements-typehint.txt @@ -27,7 +27,7 @@ attrs==24.2.0 # jsonschema # localstack-twisted # referencing -aws-cdk-asset-awscli-v1==2.2.212 +aws-cdk-asset-awscli-v1==2.2.213 # via aws-cdk-lib aws-cdk-asset-kubectl-v20==2.1.3 # via aws-cdk-lib @@ -35,9 +35,9 @@ aws-cdk-asset-node-proxy-agent-v6==2.1.0 # via aws-cdk-lib aws-cdk-cloud-assembly-schema==38.0.1 # via aws-cdk-lib -aws-cdk-lib==2.167.1 +aws-cdk-lib==2.171.0 # via localstack-core -aws-sam-translator==1.92.0 +aws-sam-translator==1.94.0 # via # cfn-lint # localstack-core @@ -45,7 +45,7 @@ aws-xray-sdk==2.14.0 # via moto-ext awscli==1.36.9 # via localstack-core -awscrt==0.23.0 +awscrt==0.23.1 # via localstack-core boto3==1.35.68 # via @@ -53,7 +53,7 @@ boto3==1.35.68 # aws-sam-translator # localstack-core # moto-ext -boto3-stubs==1.35.64 +boto3-stubs==1.35.69 # via localstack-core (pyproject.toml) botocore==1.35.68 # via @@ -64,7 +64,7 @@ botocore==1.35.68 # localstack-snapshot # moto-ext # s3transfer -botocore-stubs==1.35.64 +botocore-stubs==1.35.69 # via boto3-stubs build==1.2.2.post1 # via @@ -103,7 +103,7 @@ constantly==23.10.4 # via localstack-twisted constructs==10.4.2 # via aws-cdk-lib -coverage==7.6.7 +coverage==7.6.8 # via # coveralls # localstack-core @@ -177,7 +177,7 @@ hyperframe==6.0.1 # via h2 hyperlink==21.0.0 # via localstack-twisted -identify==2.6.2 +identify==2.6.3 # via pre-commit idna==3.10 # via @@ -202,7 +202,7 @@ jmespath==1.0.1 # botocore joserfc==1.0.0 # via moto-ext -jpype1-ext==0.0.1 +jpype1-ext==0.0.2 # via localstack-core jsii==1.105.0 # via @@ -272,7 +272,7 @@ mypy-boto3-acm-pca==1.35.38 # via boto3-stubs mypy-boto3-amplify==1.35.41 # via boto3-stubs -mypy-boto3-apigateway==1.35.25 +mypy-boto3-apigateway==1.35.67 # via boto3-stubs mypy-boto3-apigatewayv2==1.35.0 # via boto3-stubs @@ -280,27 +280,27 @@ mypy-boto3-appconfig==1.35.64 # via boto3-stubs mypy-boto3-appconfigdata==1.35.0 # via boto3-stubs -mypy-boto3-application-autoscaling==1.35.0 +mypy-boto3-application-autoscaling==1.35.67 # via boto3-stubs -mypy-boto3-appsync==1.35.52 +mypy-boto3-appsync==1.35.67 # via boto3-stubs mypy-boto3-athena==1.35.44 # via boto3-stubs -mypy-boto3-autoscaling==1.35.64 +mypy-boto3-autoscaling==1.35.68 # via boto3-stubs mypy-boto3-backup==1.35.10 # via boto3-stubs mypy-boto3-batch==1.35.57 # via boto3-stubs -mypy-boto3-ce==1.35.22 +mypy-boto3-ce==1.35.68 # via boto3-stubs mypy-boto3-cloudcontrol==1.35.61 # via boto3-stubs mypy-boto3-cloudformation==1.35.64 # via boto3-stubs -mypy-boto3-cloudfront==1.35.58 +mypy-boto3-cloudfront==1.35.67 # via boto3-stubs -mypy-boto3-cloudtrail==1.35.60 +mypy-boto3-cloudtrail==1.35.67 # via boto3-stubs mypy-boto3-cloudwatch==1.35.63 # via boto3-stubs @@ -308,7 +308,7 @@ mypy-boto3-codecommit==1.35.0 # via boto3-stubs mypy-boto3-cognito-identity==1.35.16 # via boto3-stubs -mypy-boto3-cognito-idp==1.35.18 +mypy-boto3-cognito-idp==1.35.68 # via boto3-stubs mypy-boto3-dms==1.35.45 # via boto3-stubs @@ -318,23 +318,23 @@ mypy-boto3-dynamodb==1.35.60 # via boto3-stubs mypy-boto3-dynamodbstreams==1.35.0 # via boto3-stubs -mypy-boto3-ec2==1.35.64 +mypy-boto3-ec2==1.35.67 # via boto3-stubs mypy-boto3-ecr==1.35.21 # via boto3-stubs -mypy-boto3-ecs==1.35.64 +mypy-boto3-ecs==1.35.66 # via boto3-stubs -mypy-boto3-efs==1.35.0 +mypy-boto3-efs==1.35.65 # via boto3-stubs mypy-boto3-eks==1.35.57 # via boto3-stubs -mypy-boto3-elasticache==1.35.36 +mypy-boto3-elasticache==1.35.67 # via boto3-stubs mypy-boto3-elasticbeanstalk==1.35.0 # via boto3-stubs -mypy-boto3-elbv2==1.35.53 +mypy-boto3-elbv2==1.35.68 # via boto3-stubs -mypy-boto3-emr==1.35.39 +mypy-boto3-emr==1.35.68 # via boto3-stubs mypy-boto3-emr-serverless==1.35.25 # via boto3-stubs @@ -348,13 +348,13 @@ mypy-boto3-fis==1.35.59 # via boto3-stubs mypy-boto3-glacier==1.35.0 # via boto3-stubs -mypy-boto3-glue==1.35.53 +mypy-boto3-glue==1.35.65 # via boto3-stubs mypy-boto3-iam==1.35.61 # via boto3-stubs mypy-boto3-identitystore==1.35.0 # via boto3-stubs -mypy-boto3-iot==1.35.63 +mypy-boto3-iot==1.35.67 # via boto3-stubs mypy-boto3-iot-data==1.35.34 # via boto3-stubs @@ -374,19 +374,19 @@ mypy-boto3-kms==1.35.0 # via boto3-stubs mypy-boto3-lakeformation==1.35.55 # via boto3-stubs -mypy-boto3-lambda==1.35.58 +mypy-boto3-lambda==1.35.68 # via boto3-stubs -mypy-boto3-logs==1.35.54 +mypy-boto3-logs==1.35.67 # via boto3-stubs mypy-boto3-managedblockchain==1.35.0 # via boto3-stubs -mypy-boto3-mediaconvert==1.35.60 +mypy-boto3-mediaconvert==1.35.66 # via boto3-stubs mypy-boto3-mediastore==1.35.0 # via boto3-stubs mypy-boto3-mq==1.35.0 # via boto3-stubs -mypy-boto3-mwaa==1.35.0 +mypy-boto3-mwaa==1.35.65 # via boto3-stubs mypy-boto3-neptune==1.35.24 # via boto3-stubs @@ -404,7 +404,7 @@ mypy-boto3-qldb==1.35.0 # via boto3-stubs mypy-boto3-qldb-session==1.35.0 # via boto3-stubs -mypy-boto3-rds==1.35.64 +mypy-boto3-rds==1.35.66 # via boto3-stubs mypy-boto3-rds-data==1.35.64 # via boto3-stubs @@ -420,11 +420,11 @@ mypy-boto3-route53==1.35.52 # via boto3-stubs mypy-boto3-route53resolver==1.35.63 # via boto3-stubs -mypy-boto3-s3==1.35.61 +mypy-boto3-s3==1.35.69 # via boto3-stubs mypy-boto3-s3control==1.35.55 # via boto3-stubs -mypy-boto3-sagemaker==1.35.61 +mypy-boto3-sagemaker==1.35.68 # via boto3-stubs mypy-boto3-sagemaker-runtime==1.35.15 # via boto3-stubs @@ -434,23 +434,23 @@ mypy-boto3-serverlessrepo==1.35.0 # via boto3-stubs mypy-boto3-servicediscovery==1.35.0 # via boto3-stubs -mypy-boto3-ses==1.35.3 +mypy-boto3-ses==1.35.68 # via boto3-stubs mypy-boto3-sesv2==1.35.53 # via boto3-stubs -mypy-boto3-sns==1.35.0 +mypy-boto3-sns==1.35.68 # via boto3-stubs mypy-boto3-sqs==1.35.0 # via boto3-stubs -mypy-boto3-ssm==1.35.21 +mypy-boto3-ssm==1.35.67 # via boto3-stubs mypy-boto3-sso-admin==1.35.0 # via boto3-stubs -mypy-boto3-stepfunctions==1.35.54 +mypy-boto3-stepfunctions==1.35.68 # via boto3-stubs mypy-boto3-sts==1.35.61 # via boto3-stubs -mypy-boto3-timestream-query==1.35.46 +mypy-boto3-timestream-query==1.35.66 # via boto3-stubs mypy-boto3-timestream-write==1.35.0 # via boto3-stubs @@ -458,7 +458,7 @@ mypy-boto3-transcribe==1.35.0 # via boto3-stubs mypy-boto3-wafv2==1.35.45 # via boto3-stubs -mypy-boto3-xray==1.35.0 +mypy-boto3-xray==1.35.67 # via boto3-stubs networkx==3.4.2 # via @@ -536,9 +536,9 @@ pyasn1==0.6.1 # via rsa pycparser==2.22 # via cffi -pydantic==2.9.2 +pydantic==2.10.1 # via aws-sam-translator -pydantic-core==2.23.4 +pydantic-core==2.27.1 # via pydantic pygments==2.18.0 # via rich @@ -562,7 +562,7 @@ pytest==8.3.3 # pytest-tinybird pytest-httpserver==1.1.0 # via localstack-core -pytest-rerunfailures==14.0 +pytest-rerunfailures==15.0 # via localstack-core pytest-split==0.10.0 # via localstack-core @@ -631,9 +631,9 @@ rsa==4.7.2 # via awscli rstr==3.2.2 # via localstack-core -ruff==0.7.4 +ruff==0.8.0 # via localstack-core -s3transfer==0.10.3 +s3transfer==0.10.4 # via # awscli # boto3 @@ -668,7 +668,7 @@ typeguard==2.13.3 # jsii types-awscrt==0.23.0 # via botocore-stubs -types-s3transfer==0.10.3 +types-s3transfer==0.10.4 # via boto3-stubs typing-extensions==4.12.2 # via @@ -785,7 +785,7 @@ urllib3==2.2.3 # opensearch-py # requests # responses -virtualenv==20.27.1 +virtualenv==20.28.0 # via pre-commit websocket-client==1.8.0 # via localstack-core @@ -796,7 +796,7 @@ werkzeug==3.1.3 # openapi-core # pytest-httpserver # rolo -wrapt==1.16.0 +wrapt==1.17.0 # via aws-xray-sdk wsproto==1.2.0 # via hypercorn From 5f19fbc6bc1a018419b9a9adf1d8bc0268b8546d Mon Sep 17 00:00:00 2001 From: Zain Zafar Date: Tue, 26 Nov 2024 10:15:38 +0000 Subject: [PATCH 07/38] Events create connection test fix (#11904) --- .../localstack/services/events/provider.py | 80 +++++++++++-------- tests/aws/services/events/test_events.py | 4 +- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/localstack-core/localstack/services/events/provider.py b/localstack-core/localstack/services/events/provider.py index e70beee2ba57b..fe920d765ab05 100644 --- a/localstack-core/localstack/services/events/provider.py +++ b/localstack-core/localstack/services/events/provider.py @@ -230,34 +230,45 @@ def on_before_stop(self): # Helper Methods for connections and api destinations ########## - def _validate_api_destination_name(self, name: str) -> None: - """Validate the API destination name according to AWS rules.""" + def _validate_api_destination_name(self, name: str) -> list[str]: + """Validate the API destination name according to AWS rules. Returns a list of validation errors.""" + errors = [] if not re.match(r"^[\.\-_A-Za-z0-9]+$", name): - raise ValidationException( - f"1 validation error detected: Value '{name}' at 'name' failed to satisfy constraint: " + errors.append( + f"Value '{name}' at 'name' failed to satisfy constraint: " "Member must satisfy regular expression pattern: [\\.\\-_A-Za-z0-9]+" ) if not (1 <= len(name) <= 64): - raise ValidationException( - f"1 validation error detected: Value '{name}' at 'name' failed to satisfy constraint: " - "Member must have length between 1 and 64" + errors.append( + f"Value '{name}' at 'name' failed to satisfy constraint: " + "Member must have length less than or equal to 64" ) + return errors - def _validate_connection_name(self, name: str) -> None: - """Validate the connection name according to AWS rules.""" + def _validate_connection_name(self, name: str) -> list[str]: + """Validate the connection name according to AWS rules. Returns a list of validation errors.""" + errors = [] if not re.match("^[\\.\\-_A-Za-z0-9]+$", name): - raise ValidationException( - f"1 validation error detected: Value '{name}' at 'name' failed to satisfy constraint: " + errors.append( + f"Value '{name}' at 'name' failed to satisfy constraint: " "Member must satisfy regular expression pattern: [\\.\\-_A-Za-z0-9]+" ) + if not (1 <= len(name) <= 64): + errors.append( + f"Value '{name}' at 'name' failed to satisfy constraint: " + "Member must have length less than or equal to 64" + ) + return errors - def _validate_auth_type(self, auth_type: str) -> None: - """Validate the authorization type is one of the allowed values.""" + def _validate_auth_type(self, auth_type: str) -> list[str]: + """Validate the authorization type. Returns a list of validation errors.""" + errors = [] if auth_type not in VALID_AUTH_TYPES: - raise ValidationException( - f"1 validation error detected: Value '{auth_type}' at 'authorizationType' failed to satisfy constraint: " + errors.append( + f"Value '{auth_type}' at 'authorizationType' failed to satisfy constraint: " f"Member must satisfy enum value set: [{', '.join(VALID_AUTH_TYPES)}]" ) + return errors def _get_connection_by_arn(self, connection_arn: str) -> Optional[Dict]: """Retrieve a connection by its ARN.""" @@ -511,12 +522,23 @@ def create_connection( description: ConnectionDescription = None, **kwargs, ) -> CreateConnectionResponse: + """Create a new connection.""" + auth_type = authorization_type + if hasattr(authorization_type, "value"): + auth_type = authorization_type.value + + errors = [] + errors.extend(self._validate_connection_name(name)) + errors.extend(self._validate_auth_type(auth_type)) + + if errors: + error_message = ( + f"{len(errors)} validation error{'s' if len(errors) > 1 else ''} detected: " + ) + error_message += "; ".join(errors) + raise ValidationException(error_message) + def create(): - auth_type = authorization_type - if hasattr(authorization_type, "value"): - auth_type = authorization_type.value - self._validate_auth_type(auth_type) - self._validate_connection_name(name) store = self.get_store(context.region, context.account_id) if name in store.connections: @@ -685,19 +707,11 @@ def create_api_destination( def create(): validation_errors = [] - if not re.match(r"^[\.\-_A-Za-z0-9]+$", name): - validation_errors.append( - f"Value '{name}' at 'name' failed to satisfy constraint: " - "Member must satisfy regular expression pattern: [\\.\\-_A-Za-z0-9]+" - ) - if not (1 <= len(name) <= 64): - validation_errors.append( - f"Value '{name}' at 'name' failed to satisfy constraint: " - "Member must have length between 1 and 64" - ) - - connection_arn_pattern = r"^arn:aws([a-z]|\-)*:events:[a-z0-9\-]+:\d{12}:connection/[\.\-_A-Za-z0-9]+/[\-A-Za-z0-9]+$" - if not re.match(connection_arn_pattern, connection_arn): + validation_errors.extend(self._validate_api_destination_name(name)) + if not re.match( + r"^arn:aws([a-z]|\-)*:events:[a-z0-9\-]+:\d{12}:connection/[\.\-_A-Za-z0-9]+/[\-A-Za-z0-9]+$", + connection_arn, + ): validation_errors.append( f"Value '{connection_arn}' at 'connectionArn' failed to satisfy constraint: " "Member must satisfy regular expression pattern: " diff --git a/tests/aws/services/events/test_events.py b/tests/aws/services/events/test_events.py index 687bf5fd198a9..fbe59dc980490 100644 --- a/tests/aws/services/events/test_events.py +++ b/tests/aws/services/events/test_events.py @@ -402,9 +402,7 @@ def _handler(_request: Request): assert oauth_request.args["oauthquery"] == "value3" @markers.aws.validated - @pytest.mark.skip( - reason="V2 provider does not support this feature yet and it also fails in V1 now" - ) + @pytest.mark.skipif(is_old_provider(), reason="V1 provider does not support this feature") def test_create_connection_validations(self, aws_client, snapshot): connection_name = "This should fail with two errors 123467890123412341234123412341234" From 0d02e67ed664a5362c59c8941553b7feae39447a Mon Sep 17 00:00:00 2001 From: Daniel Fangl Date: Tue, 26 Nov 2024 14:55:03 +0100 Subject: [PATCH 08/38] Add nodejs22.x AWS Lambda runtime (#11929) --- .../localstack/services/lambda_/runtimes.py | 7 +- .../lambda_/test_lambda_api.snapshot.json | 51 +- .../lambda_/test_lambda_api.validation.json | 26 +- .../lambda_/test_lambda_common.snapshot.json | 444 ++++++++++++++---- .../test_lambda_common.validation.json | 197 ++++---- .../test_lambda_runtimes.snapshot.json | 130 +++-- .../test_lambda_runtimes.validation.json | 67 +-- 7 files changed, 635 insertions(+), 287 deletions(-) diff --git a/localstack-core/localstack/services/lambda_/runtimes.py b/localstack-core/localstack/services/lambda_/runtimes.py index ac818bbe06c62..01789f468df8e 100644 --- a/localstack-core/localstack/services/lambda_/runtimes.py +++ b/localstack-core/localstack/services/lambda_/runtimes.py @@ -27,7 +27,7 @@ # 6. Review special tests including: # a) [ext] tests.aws.services.lambda_.test_lambda_endpoint_injection # 7. Before merging, run the ext integration tests to cover transparent endpoint injection testing. -# 8. Add the new runtime to the K8 image build: https://github.com/localstack/lambda-cve-mitigation +# 8. Add the new runtime to the K8 image build: https://github.com/localstack/lambda-images # 9. Inform the web team to update the resource browser (consider offering an endpoint in the future) # Mapping from a) AWS Lambda runtime identifier => b) official AWS image on Amazon ECR Public @@ -36,7 +36,7 @@ # => Synchronize the order with the "Supported runtimes" under "AWS Lambda runtimes" (a) # => Add comments for deprecated runtimes using => => IMAGE_MAPPING: dict[Runtime, str] = { - # "nodejs22.x": "nodejs:22", expected November 2024 + Runtime.nodejs22_x: "nodejs:22", Runtime.nodejs20_x: "nodejs:20", Runtime.nodejs18_x: "nodejs:18", Runtime.nodejs16_x: "nodejs:16", @@ -111,6 +111,7 @@ # => Remove deprecated runtimes from this testing list RUNTIMES_AGGREGATED = { "nodejs": [ + Runtime.nodejs22_x, Runtime.nodejs20_x, Runtime.nodejs18_x, Runtime.nodejs16_x, @@ -153,6 +154,6 @@ SNAP_START_SUPPORTED_RUNTIMES = [Runtime.java11, Runtime.java17, Runtime.java21] # An ordered list of all Lambda runtimes considered valid by AWS. Matching snapshots in test_create_lambda_exceptions -VALID_RUNTIMES: str = "[nodejs20.x, provided.al2023, python3.12, python3.13, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9]" +VALID_RUNTIMES: str = "[nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9]" # An ordered list of all Lambda runtimes for layers considered valid by AWS. Matching snapshots in test_layer_exceptions VALID_LAYER_RUNTIMES: str = "[ruby2.6, dotnetcore1.0, python3.7, nodejs8.10, nasa, ruby2.7, python2.7-greengrass, dotnetcore2.0, python3.8, java21, dotnet6, dotnetcore2.1, python3.9, java11, nodejs6.10, provided, dotnetcore3.1, dotnet8, java17, nodejs, nodejs4.3, java8.al2, go1.x, nodejs20.x, go1.9, byol, nodejs10.x, provided.al2023, nodejs22.x, python3.10, java8, nodejs12.x, python3.11, nodejs8.x, python3.12, nodejs14.x, nodejs8.9, python3.13, nodejs16.x, provided.al2, nodejs4.3-edge, nodejs18.x, ruby3.2, python3.4, ruby3.3, ruby2.5, python3.6, python2.7]" diff --git a/tests/aws/services/lambda_/test_lambda_api.snapshot.json b/tests/aws/services/lambda_/test_lambda_api.snapshot.json index b60e0d4965f66..2a586a29b4c3b 100644 --- a/tests/aws/services/lambda_/test_lambda_api.snapshot.json +++ b/tests/aws/services/lambda_/test_lambda_api.snapshot.json @@ -7836,7 +7836,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_create_lambda_exceptions": { - "recorded-date": "18-11-2024, 15:57:03", + "recorded-date": "26-11-2024, 09:27:31", "recorded-content": { "invalid_role_arn_exc": { "Error": { @@ -7851,10 +7851,10 @@ "invalid_runtime_exc": { "Error": { "Code": "InvalidParameterValueException", - "Message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN" + "Message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN" }, "Type": "User", - "message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN", + "message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 400 @@ -7863,10 +7863,10 @@ "uppercase_runtime_exc": { "Error": { "Code": "InvalidParameterValueException", - "Message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN" + "Message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN" }, "Type": "User", - "message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN", + "message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 400 @@ -7908,7 +7908,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_update_lambda_exceptions": { - "recorded-date": "18-11-2024, 15:57:06", + "recorded-date": "26-11-2024, 09:27:33", "recorded-content": { "invalid_role_arn_exc": { "Error": { @@ -7923,10 +7923,10 @@ "invalid_runtime_exc": { "Error": { "Code": "InvalidParameterValueException", - "Message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN" + "Message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN" }, "Type": "User", - "message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN", + "message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 400 @@ -7935,10 +7935,10 @@ "uppercase_runtime_exc": { "Error": { "Code": "InvalidParameterValueException", - "Message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN" + "Message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN" }, "Type": "User", - "message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN", + "message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 400 @@ -8248,7 +8248,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_exceptions": { - "recorded-date": "18-11-2024, 15:57:22", + "recorded-date": "26-11-2024, 09:27:46", "recorded-content": { "publish_result": { "CompatibleArchitectures": [ @@ -8426,7 +8426,7 @@ "publish_layer_version_exc_invalid_runtime_arch": { "Error": { "Code": "ValidationException", - "Message": "2 validation errors detected: Value '[invalidruntime]' at 'compatibleRuntimes' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9]; Value '[invalidarch]' at 'compatibleArchitectures' failed to satisfy constraint: Member must satisfy constraint: [Member must satisfy enum value set: [x86_64, arm64]]" + "Message": "2 validation errors detected: Value '[invalidruntime]' at 'compatibleRuntimes' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9]; Value '[invalidarch]' at 'compatibleArchitectures' failed to satisfy constraint: Member must satisfy constraint: [Member must satisfy enum value set: [x86_64, arm64]]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -8436,7 +8436,7 @@ "publish_layer_version_exc_partially_invalid_values": { "Error": { "Code": "ValidationException", - "Message": "2 validation errors detected: Value '[invalidruntime, invalidruntime2, nodejs20.x]' at 'compatibleRuntimes' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9]; Value '[invalidarch, x86_64]' at 'compatibleArchitectures' failed to satisfy constraint: Member must satisfy constraint: [Member must satisfy enum value set: [x86_64, arm64]]" + "Message": "2 validation errors detected: Value '[invalidruntime, invalidruntime2, nodejs20.x]' at 'compatibleRuntimes' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, java8.al2, ruby3.2, python3.8, python3.9]; Value '[invalidarch, x86_64]' at 'compatibleArchitectures' failed to satisfy constraint: Member must satisfy constraint: [Member must satisfy enum value set: [x86_64, arm64]]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -13759,7 +13759,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_compatibilities[runtimes0]": { - "recorded-date": "18-11-2024, 15:57:09", + "recorded-date": "26-11-2024, 09:27:34", "recorded-content": { "publish_result": { "CompatibleArchitectures": [ @@ -13767,6 +13767,7 @@ "x86_64" ], "CompatibleRuntimes": [ + "nodejs22.x", "nodejs20.x", "nodejs18.x", "nodejs16.x", @@ -13779,8 +13780,7 @@ "python3.9", "python3.8", "python3.7", - "java21", - "java17" + "java21" ], "Content": { "CodeSha256": "", @@ -13800,7 +13800,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_compatibilities[runtimes1]": { - "recorded-date": "18-11-2024, 15:57:14", + "recorded-date": "26-11-2024, 09:27:38", "recorded-content": { "publish_result": { "CompatibleArchitectures": [ @@ -13808,6 +13808,7 @@ "x86_64" ], "CompatibleRuntimes": [ + "java17", "java11", "java8.al2", "java8", @@ -16304,7 +16305,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[java8]": { - "recorded-date": "18-11-2024, 15:57:00", + "recorded-date": "26-11-2024, 09:27:29", "recorded-content": { "deprecation_error": { "Error": { @@ -16321,7 +16322,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[go1.x]": { - "recorded-date": "18-11-2024, 15:57:00", + "recorded-date": "26-11-2024, 09:27:29", "recorded-content": { "deprecation_error": { "Error": { @@ -16338,7 +16339,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[provided]": { - "recorded-date": "18-11-2024, 15:57:01", + "recorded-date": "26-11-2024, 09:27:30", "recorded-content": { "deprecation_error": { "Error": { @@ -16355,7 +16356,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[ruby2.7]": { - "recorded-date": "18-11-2024, 15:57:01", + "recorded-date": "26-11-2024, 09:27:30", "recorded-content": { "deprecation_error": { "Error": { @@ -16372,7 +16373,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[nodejs14.x]": { - "recorded-date": "18-11-2024, 15:57:01", + "recorded-date": "26-11-2024, 09:27:30", "recorded-content": { "deprecation_error": { "Error": { @@ -16389,7 +16390,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[python3.7]": { - "recorded-date": "18-11-2024, 15:57:01", + "recorded-date": "26-11-2024, 09:27:30", "recorded-content": { "deprecation_error": { "Error": { @@ -16406,7 +16407,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[dotnetcore3.1]": { - "recorded-date": "18-11-2024, 15:57:02", + "recorded-date": "26-11-2024, 09:27:30", "recorded-content": { "deprecation_error": { "Error": { @@ -16423,7 +16424,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[nodejs12.x]": { - "recorded-date": "18-11-2024, 15:57:02", + "recorded-date": "26-11-2024, 09:27:30", "recorded-content": { "deprecation_error": { "Error": { diff --git a/tests/aws/services/lambda_/test_lambda_api.validation.json b/tests/aws/services/lambda_/test_lambda_api.validation.json index 463cb8b483a46..97b90d0083c9a 100644 --- a/tests/aws/services/lambda_/test_lambda_api.validation.json +++ b/tests/aws/services/lambda_/test_lambda_api.validation.json @@ -57,7 +57,7 @@ "last_validated_date": "2024-04-10T08:58:47+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_create_lambda_exceptions": { - "last_validated_date": "2024-11-18T15:57:03+00:00" + "last_validated_date": "2024-11-26T09:27:31+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_delete_on_nonexisting_version": { "last_validated_date": "2024-09-12T11:29:32+00:00" @@ -411,7 +411,7 @@ "last_validated_date": "2024-09-12T11:29:23+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_update_lambda_exceptions": { - "last_validated_date": "2024-11-18T15:57:06+00:00" + "last_validated_date": "2024-11-26T09:27:33+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_vpc_config": { "last_validated_date": "2024-09-12T11:34:40+00:00" @@ -429,13 +429,13 @@ "last_validated_date": "2024-04-10T09:10:37+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_compatibilities[runtimes0]": { - "last_validated_date": "2024-11-18T15:57:09+00:00" + "last_validated_date": "2024-11-26T09:27:34+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_compatibilities[runtimes1]": { - "last_validated_date": "2024-11-18T15:57:13+00:00" + "last_validated_date": "2024-11-26T09:27:38+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_exceptions": { - "last_validated_date": "2024-11-18T15:57:22+00:00" + "last_validated_date": "2024-11-26T09:27:46+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_function_exceptions": { "last_validated_date": "2024-04-10T09:23:18+00:00" @@ -639,27 +639,27 @@ "last_validated_date": "2024-06-12T14:19:11+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[dotnetcore3.1]": { - "last_validated_date": "2024-11-18T15:57:02+00:00" + "last_validated_date": "2024-11-26T09:27:30+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[go1.x]": { - "last_validated_date": "2024-11-18T15:57:00+00:00" + "last_validated_date": "2024-11-26T09:27:29+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[java8]": { - "last_validated_date": "2024-11-18T15:57:00+00:00" + "last_validated_date": "2024-11-26T09:27:29+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[nodejs12.x]": { - "last_validated_date": "2024-11-18T15:57:02+00:00" + "last_validated_date": "2024-11-26T09:27:30+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[nodejs14.x]": { - "last_validated_date": "2024-11-18T15:57:01+00:00" + "last_validated_date": "2024-11-26T09:27:30+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[provided]": { - "last_validated_date": "2024-11-18T15:57:01+00:00" + "last_validated_date": "2024-11-26T09:27:30+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[python3.7]": { - "last_validated_date": "2024-11-18T15:57:01+00:00" + "last_validated_date": "2024-11-26T09:27:30+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[ruby2.7]": { - "last_validated_date": "2024-11-18T15:57:01+00:00" + "last_validated_date": "2024-11-26T09:27:30+00:00" } } diff --git a/tests/aws/services/lambda_/test_lambda_common.snapshot.json b/tests/aws/services/lambda_/test_lambda_common.snapshot.json index bdaba1ab850f3..cc5b9054d5f5e 100644 --- a/tests/aws/services/lambda_/test_lambda_common.snapshot.json +++ b/tests/aws/services/lambda_/test_lambda_common.snapshot.json @@ -1,70 +1,70 @@ { "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.8]": { - "recorded-date": "18-11-2024, 15:47:54", + "recorded-date": "26-11-2024, 09:28:27", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java11]": { - "recorded-date": "18-11-2024, 15:48:15", + "recorded-date": "26-11-2024, 09:29:13", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[provided.al2]": { - "recorded-date": "18-11-2024, 15:48:57", + "recorded-date": "26-11-2024, 09:31:05", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java8.al2]": { - "recorded-date": "18-11-2024, 15:48:20", + "recorded-date": "26-11-2024, 09:29:18", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.2]": { - "recorded-date": "18-11-2024, 15:48:25", + "recorded-date": "26-11-2024, 09:29:22", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.11]": { - "recorded-date": "18-11-2024, 15:47:38", + "recorded-date": "26-11-2024, 09:28:14", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java17]": { - "recorded-date": "18-11-2024, 15:48:04", + "recorded-date": "26-11-2024, 09:29:09", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs18.x]": { - "recorded-date": "18-11-2024, 15:47:18", + "recorded-date": "26-11-2024, 09:27:58", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java21]": { - "recorded-date": "18-11-2024, 15:47:59", + "recorded-date": "26-11-2024, 09:29:04", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[provided.al2023]": { - "recorded-date": "18-11-2024, 15:48:48", + "recorded-date": "26-11-2024, 09:30:57", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.9]": { - "recorded-date": "18-11-2024, 15:47:48", + "recorded-date": "26-11-2024, 09:28:22", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.10]": { - "recorded-date": "18-11-2024, 15:47:43", + "recorded-date": "26-11-2024, 09:28:18", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.12]": { - "recorded-date": "18-11-2024, 15:47:33", + "recorded-date": "26-11-2024, 09:28:11", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs20.x]": { - "recorded-date": "18-11-2024, 15:47:12", + "recorded-date": "26-11-2024, 09:27:54", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[dotnet6]": { - "recorded-date": "18-11-2024, 15:48:36", + "recorded-date": "26-11-2024, 09:30:41", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs16.x]": { - "recorded-date": "18-11-2024, 15:47:23", + "recorded-date": "26-11-2024, 09:28:02", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.8]": { - "recorded-date": "18-11-2024, 15:49:26", + "recorded-date": "26-11-2024, 09:31:29", "recorded-content": { "create_function_result": { "Architectures": [ @@ -205,7 +205,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java11]": { - "recorded-date": "18-11-2024, 15:49:37", + "recorded-date": "26-11-2024, 09:31:44", "recorded-content": { "create_function_result": { "Architectures": [ @@ -344,7 +344,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[provided.al2]": { - "recorded-date": "18-11-2024, 15:50:08", + "recorded-date": "26-11-2024, 09:33:29", "recorded-content": { "create_function_result": { "Architectures": [ @@ -477,7 +477,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java8.al2]": { - "recorded-date": "18-11-2024, 15:49:41", + "recorded-date": "26-11-2024, 09:31:47", "recorded-content": { "create_function_result": { "Architectures": [ @@ -616,7 +616,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.2]": { - "recorded-date": "18-11-2024, 15:49:44", + "recorded-date": "26-11-2024, 09:31:49", "recorded-content": { "create_function_result": { "Architectures": [ @@ -761,7 +761,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.11]": { - "recorded-date": "18-11-2024, 15:49:16", + "recorded-date": "26-11-2024, 09:31:22", "recorded-content": { "create_function_result": { "Architectures": [ @@ -902,7 +902,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java17]": { - "recorded-date": "18-11-2024, 15:49:33", + "recorded-date": "26-11-2024, 09:31:41", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1037,7 +1037,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs18.x]": { - "recorded-date": "18-11-2024, 15:49:03", + "recorded-date": "26-11-2024, 09:31:13", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1178,7 +1178,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java21]": { - "recorded-date": "18-11-2024, 15:49:29", + "recorded-date": "26-11-2024, 09:31:38", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1313,7 +1313,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[provided.al2023]": { - "recorded-date": "18-11-2024, 15:50:03", + "recorded-date": "26-11-2024, 09:33:25", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1446,7 +1446,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.9]": { - "recorded-date": "18-11-2024, 15:49:23", + "recorded-date": "26-11-2024, 09:31:26", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1587,7 +1587,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.10]": { - "recorded-date": "18-11-2024, 15:49:19", + "recorded-date": "26-11-2024, 09:31:24", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1728,7 +1728,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.12]": { - "recorded-date": "18-11-2024, 15:49:13", + "recorded-date": "26-11-2024, 09:31:20", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1871,7 +1871,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs20.x]": { - "recorded-date": "18-11-2024, 15:49:00", + "recorded-date": "26-11-2024, 09:31:10", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2010,7 +2010,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[dotnet6]": { - "recorded-date": "18-11-2024, 15:49:51", + "recorded-date": "26-11-2024, 09:32:01", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2155,7 +2155,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs16.x]": { - "recorded-date": "18-11-2024, 15:49:07", + "recorded-date": "26-11-2024, 09:31:15", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2296,7 +2296,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.8]": { - "recorded-date": "18-11-2024, 15:50:33", + "recorded-date": "26-11-2024, 09:33:50", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2358,7 +2358,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java11]": { - "recorded-date": "18-11-2024, 15:50:43", + "recorded-date": "26-11-2024, 09:34:06", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2420,7 +2420,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[provided.al2]": { - "recorded-date": "18-11-2024, 15:51:07", + "recorded-date": "26-11-2024, 09:35:05", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2481,7 +2481,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java8.al2]": { - "recorded-date": "18-11-2024, 15:50:47", + "recorded-date": "26-11-2024, 09:34:09", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2543,7 +2543,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.2]": { - "recorded-date": "18-11-2024, 15:50:50", + "recorded-date": "26-11-2024, 09:34:11", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2605,7 +2605,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.11]": { - "recorded-date": "18-11-2024, 15:50:25", + "recorded-date": "26-11-2024, 09:33:44", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2668,7 +2668,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java17]": { - "recorded-date": "18-11-2024, 15:50:40", + "recorded-date": "26-11-2024, 09:34:03", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2730,7 +2730,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs18.x]": { - "recorded-date": "18-11-2024, 15:50:13", + "recorded-date": "26-11-2024, 09:33:36", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2792,7 +2792,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java21]": { - "recorded-date": "18-11-2024, 15:50:37", + "recorded-date": "26-11-2024, 09:34:00", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2854,7 +2854,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[provided.al2023]": { - "recorded-date": "18-11-2024, 15:51:03", + "recorded-date": "26-11-2024, 09:35:00", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2915,7 +2915,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.9]": { - "recorded-date": "18-11-2024, 15:50:30", + "recorded-date": "26-11-2024, 09:33:48", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2978,7 +2978,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.10]": { - "recorded-date": "18-11-2024, 15:50:27", + "recorded-date": "26-11-2024, 09:33:46", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3041,7 +3041,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.12]": { - "recorded-date": "18-11-2024, 15:50:22", + "recorded-date": "26-11-2024, 09:33:42", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3104,7 +3104,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs20.x]": { - "recorded-date": "18-11-2024, 15:50:11", + "recorded-date": "26-11-2024, 09:33:34", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3166,7 +3166,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[dotnet6]": { - "recorded-date": "18-11-2024, 15:50:56", + "recorded-date": "26-11-2024, 09:34:22", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3228,7 +3228,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs16.x]": { - "recorded-date": "18-11-2024, 15:50:16", + "recorded-date": "26-11-2024, 09:33:38", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3290,7 +3290,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.8]": { - "recorded-date": "18-11-2024, 15:51:20", + "recorded-date": "26-11-2024, 09:35:17", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3343,7 +3343,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java11]": { - "recorded-date": "18-11-2024, 15:51:17", + "recorded-date": "26-11-2024, 09:35:23", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3396,7 +3396,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java8.al2]": { - "recorded-date": "18-11-2024, 15:51:48", + "recorded-date": "26-11-2024, 09:35:33", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3449,7 +3449,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.2]": { - "recorded-date": "18-11-2024, 15:51:51", + "recorded-date": "26-11-2024, 09:35:20", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3502,7 +3502,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.11]": { - "recorded-date": "18-11-2024, 15:51:10", + "recorded-date": "26-11-2024, 09:35:49", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3555,7 +3555,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java17]": { - "recorded-date": "18-11-2024, 15:51:41", + "recorded-date": "26-11-2024, 09:35:45", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3608,7 +3608,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs18.x]": { - "recorded-date": "18-11-2024, 15:51:35", + "recorded-date": "26-11-2024, 09:35:35", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3661,7 +3661,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java21]": { - "recorded-date": "18-11-2024, 15:51:26", + "recorded-date": "26-11-2024, 09:35:30", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3714,7 +3714,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.9]": { - "recorded-date": "18-11-2024, 15:51:13", + "recorded-date": "26-11-2024, 09:35:37", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3767,7 +3767,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.10]": { - "recorded-date": "18-11-2024, 15:51:44", + "recorded-date": "26-11-2024, 09:35:11", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3820,7 +3820,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.12]": { - "recorded-date": "18-11-2024, 15:51:29", + "recorded-date": "26-11-2024, 09:35:25", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3873,7 +3873,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs20.x]": { - "recorded-date": "18-11-2024, 15:51:23", + "recorded-date": "26-11-2024, 09:35:47", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3926,7 +3926,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[dotnet6]": { - "recorded-date": "18-11-2024, 15:52:01", + "recorded-date": "26-11-2024, 09:35:40", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3979,7 +3979,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs16.x]": { - "recorded-date": "18-11-2024, 15:51:32", + "recorded-date": "26-11-2024, 09:35:27", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4032,47 +4032,47 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs20.x]": { - "recorded-date": "18-11-2024, 15:52:37", + "recorded-date": "26-11-2024, 09:38:09", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs18.x]": { - "recorded-date": "18-11-2024, 15:53:05", + "recorded-date": "26-11-2024, 09:37:43", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs16.x]": { - "recorded-date": "18-11-2024, 15:53:02", + "recorded-date": "26-11-2024, 09:36:44", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.8]": { - "recorded-date": "18-11-2024, 15:52:33", + "recorded-date": "26-11-2024, 09:36:15", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.9]": { - "recorded-date": "18-11-2024, 15:52:08", + "recorded-date": "26-11-2024, 09:37:45", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.10]": { - "recorded-date": "18-11-2024, 15:53:30", + "recorded-date": "26-11-2024, 09:35:56", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.11]": { - "recorded-date": "18-11-2024, 15:52:04", + "recorded-date": "26-11-2024, 09:38:12", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.12]": { - "recorded-date": "18-11-2024, 15:52:58", + "recorded-date": "26-11-2024, 09:36:40", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.2]": { - "recorded-date": "18-11-2024, 15:54:18", + "recorded-date": "26-11-2024, 09:36:18", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[dotnet8]": { - "recorded-date": "18-11-2024, 15:48:42", + "recorded-date": "26-11-2024, 09:30:52", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[dotnet8]": { - "recorded-date": "18-11-2024, 15:49:54", + "recorded-date": "26-11-2024, 09:32:13", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4219,7 +4219,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[dotnet8]": { - "recorded-date": "18-11-2024, 15:51:00", + "recorded-date": "26-11-2024, 09:34:30", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4281,7 +4281,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[dotnet8]": { - "recorded-date": "18-11-2024, 15:51:54", + "recorded-date": "26-11-2024, 09:35:15", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4334,35 +4334,35 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java17]": { - "recorded-date": "18-11-2024, 15:53:27", + "recorded-date": "26-11-2024, 09:38:07", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java21]": { - "recorded-date": "18-11-2024, 15:52:54", + "recorded-date": "26-11-2024, 09:36:54", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java11]": { - "recorded-date": "18-11-2024, 15:52:30", + "recorded-date": "26-11-2024, 09:36:37", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java8.al2]": { - "recorded-date": "18-11-2024, 15:54:14", + "recorded-date": "26-11-2024, 09:37:40", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[dotnet6]": { - "recorded-date": "18-11-2024, 15:54:43", + "recorded-date": "26-11-2024, 09:37:55", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[dotnet8]": { - "recorded-date": "18-11-2024, 15:54:29", + "recorded-date": "26-11-2024, 09:36:12", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.3]": { - "recorded-date": "18-11-2024, 15:48:31", + "recorded-date": "26-11-2024, 09:29:26", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.3]": { - "recorded-date": "18-11-2024, 15:49:47", + "recorded-date": "26-11-2024, 09:31:52", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4507,7 +4507,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.3]": { - "recorded-date": "18-11-2024, 15:50:53", + "recorded-date": "26-11-2024, 09:34:14", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4569,7 +4569,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.3]": { - "recorded-date": "18-11-2024, 15:51:57", + "recorded-date": "26-11-2024, 09:35:08", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4622,15 +4622,15 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.3]": { - "recorded-date": "18-11-2024, 15:54:34", + "recorded-date": "26-11-2024, 09:35:53", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.13]": { - "recorded-date": "18-11-2024, 15:47:28", + "recorded-date": "26-11-2024, 09:28:06", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.13]": { - "recorded-date": "18-11-2024, 15:49:10", + "recorded-date": "26-11-2024, 09:31:18", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4773,7 +4773,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.13]": { - "recorded-date": "18-11-2024, 15:50:19", + "recorded-date": "26-11-2024, 09:33:40", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4836,7 +4836,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.13]": { - "recorded-date": "18-11-2024, 15:51:38", + "recorded-date": "26-11-2024, 09:35:13", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4889,7 +4889,269 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.13]": { - "recorded-date": "18-11-2024, 15:53:09", + "recorded-date": "26-11-2024, 09:35:58", + "recorded-content": {} + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs22.x]": { + "recorded-date": "26-11-2024, 09:27:50", + "recorded-content": {} + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs22.x]": { + "recorded-date": "26-11-2024, 09:31:08", + "recorded-content": { + "create_function_result": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "Environment": { + "Variables": { + "TEST_KEY": "TEST_VAL" + } + }, + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "index.handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "nodejs22.x", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "invocation_result_payload": { + "ctx": { + "aws_request_id": "", + "function_name": "", + "function_version": "$LATEST", + "invoked_function_arn": "arn::lambda::111111111111:function:", + "log_group_name": "/aws/lambda/", + "log_stream_name": "", + "remaining_time_in_millis": "" + }, + "environment": { + "AWS_ACCESS_KEY_ID": "", + "AWS_DEFAULT_REGION": "", + "AWS_EXECUTION_ENV": "AWS_Lambda_nodejs22.x", + "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "1024", + "AWS_LAMBDA_FUNCTION_NAME": "", + "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", + "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", + "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", + "AWS_LAMBDA_LOG_STREAM_NAME": "", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", + "AWS_REGION": "", + "AWS_SECRET_ACCESS_KEY": "", + "AWS_SESSION_TOKEN": "", + "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", + "LAMBDA_RUNTIME_DIR": "/var/runtime", + "LAMBDA_TASK_ROOT": "/var/task", + "LANG": "en_US.UTF-8", + "LD_LIBRARY_PATH": "/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", + "NODE_PATH": "/opt/nodejs/node22/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules:/var/runtime:/var/task", + "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", + "PWD": "/var/task", + "SHLVL": "0", + "TEST_KEY": "TEST_VAL", + "TZ": ":UTC", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", + "_AWS_XRAY_DAEMON_PORT": "2000", + "_HANDLER": "index.handler", + "_X_AMZN_TRACE_ID": "" + }, + "packages": [] + }, + "invocation_result_payload_qualified": { + "ctx": { + "aws_request_id": "", + "function_name": "", + "function_version": "$LATEST", + "invoked_function_arn": "arn::lambda::111111111111:function::$LATEST", + "log_group_name": "/aws/lambda/", + "log_stream_name": "", + "remaining_time_in_millis": "" + }, + "environment": { + "AWS_ACCESS_KEY_ID": "", + "AWS_DEFAULT_REGION": "", + "AWS_EXECUTION_ENV": "AWS_Lambda_nodejs22.x", + "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "1024", + "AWS_LAMBDA_FUNCTION_NAME": "", + "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", + "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", + "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", + "AWS_LAMBDA_LOG_STREAM_NAME": "", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", + "AWS_REGION": "", + "AWS_SECRET_ACCESS_KEY": "", + "AWS_SESSION_TOKEN": "", + "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", + "LAMBDA_RUNTIME_DIR": "/var/runtime", + "LAMBDA_TASK_ROOT": "/var/task", + "LANG": "en_US.UTF-8", + "LD_LIBRARY_PATH": "/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", + "NODE_PATH": "/opt/nodejs/node22/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules:/var/runtime:/var/task", + "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", + "PWD": "/var/task", + "SHLVL": "0", + "TEST_KEY": "TEST_VAL", + "TZ": ":UTC", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", + "_AWS_XRAY_DAEMON_PORT": "2000", + "_HANDLER": "index.handler", + "_X_AMZN_TRACE_ID": "" + }, + "packages": [] + } + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs22.x]": { + "recorded-date": "26-11-2024, 09:33:31", + "recorded-content": { + "create_function_result": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "index.handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "nodejs22.x", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "error_result": { + "ExecutedVersion": "$LATEST", + "FunctionError": "Unhandled", + "Payload": { + "errorType": "Error", + "errorMessage": "Error: some_error_msg", + "trace": "" + }, + "StatusCode": 200, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs22.x]": { + "recorded-date": "26-11-2024, 09:35:42", + "recorded-content": { + "create_function_result": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "Environment": { + "Variables": { + "AWS_LAMBDA_EXEC_WRAPPER": "/var/task/environment_wrapper" + } + }, + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "index.handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "nodejs22.x", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs22.x]": { + "recorded-date": "26-11-2024, 09:37:57", "recorded-content": {} } } diff --git a/tests/aws/services/lambda_/test_lambda_common.validation.json b/tests/aws/services/lambda_/test_lambda_common.validation.json index 4ecddd2c525c0..5eb2b062f413c 100644 --- a/tests/aws/services/lambda_/test_lambda_common.validation.json +++ b/tests/aws/services/lambda_/test_lambda_common.validation.json @@ -1,275 +1,290 @@ { "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[dotnet6]": { - "last_validated_date": "2024-11-18T15:54:42+00:00" + "last_validated_date": "2024-11-26T09:37:54+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[dotnet8]": { - "last_validated_date": "2024-11-18T15:54:28+00:00" + "last_validated_date": "2024-11-26T09:36:12+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java11]": { - "last_validated_date": "2024-11-18T15:52:29+00:00" + "last_validated_date": "2024-11-26T09:36:37+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java17]": { - "last_validated_date": "2024-11-18T15:53:26+00:00" + "last_validated_date": "2024-11-26T09:38:07+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java21]": { - "last_validated_date": "2024-11-18T15:52:54+00:00" + "last_validated_date": "2024-11-26T09:36:53+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java8.al2]": { - "last_validated_date": "2024-11-18T15:54:13+00:00" + "last_validated_date": "2024-11-26T09:37:40+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs16.x]": { - "last_validated_date": "2024-11-18T15:53:01+00:00" + "last_validated_date": "2024-11-26T09:36:43+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs18.x]": { - "last_validated_date": "2024-11-18T15:53:05+00:00" + "last_validated_date": "2024-11-26T09:37:42+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs20.x]": { - "last_validated_date": "2024-11-18T15:52:36+00:00" + "last_validated_date": "2024-11-26T09:38:09+00:00" + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs22.x]": { + "last_validated_date": "2024-11-26T09:37:57+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.10]": { - "last_validated_date": "2024-11-18T15:53:30+00:00" + "last_validated_date": "2024-11-26T09:35:55+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.11]": { - "last_validated_date": "2024-11-18T15:52:04+00:00" + "last_validated_date": "2024-11-26T09:38:12+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.12]": { - "last_validated_date": "2024-11-18T15:52:57+00:00" + "last_validated_date": "2024-11-26T09:36:40+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.13]": { - "last_validated_date": "2024-11-18T15:53:09+00:00" + "last_validated_date": "2024-11-26T09:35:58+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.8]": { - "last_validated_date": "2024-11-18T15:52:32+00:00" + "last_validated_date": "2024-11-26T09:36:14+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.9]": { - "last_validated_date": "2024-11-18T15:52:07+00:00" + "last_validated_date": "2024-11-26T09:37:45+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.2]": { - "last_validated_date": "2024-11-18T15:54:18+00:00" + "last_validated_date": "2024-11-26T09:36:18+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.3]": { - "last_validated_date": "2024-11-18T15:54:33+00:00" + "last_validated_date": "2024-11-26T09:35:53+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[dotnet6]": { - "last_validated_date": "2024-11-18T15:48:36+00:00" + "last_validated_date": "2024-11-26T09:30:41+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[dotnet8]": { - "last_validated_date": "2024-11-18T15:48:41+00:00" + "last_validated_date": "2024-11-26T09:30:52+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java11]": { - "last_validated_date": "2024-11-18T15:48:14+00:00" + "last_validated_date": "2024-11-26T09:29:13+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java17]": { - "last_validated_date": "2024-11-18T15:48:04+00:00" + "last_validated_date": "2024-11-26T09:29:09+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java21]": { - "last_validated_date": "2024-11-18T15:47:59+00:00" + "last_validated_date": "2024-11-26T09:29:04+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java8.al2]": { - "last_validated_date": "2024-11-18T15:48:20+00:00" + "last_validated_date": "2024-11-26T09:29:18+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs16.x]": { - "last_validated_date": "2024-11-18T15:47:23+00:00" + "last_validated_date": "2024-11-26T09:28:02+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs18.x]": { - "last_validated_date": "2024-11-18T15:47:17+00:00" + "last_validated_date": "2024-11-26T09:27:58+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs20.x]": { - "last_validated_date": "2024-11-18T15:47:12+00:00" + "last_validated_date": "2024-11-26T09:27:54+00:00" + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs22.x]": { + "last_validated_date": "2024-11-26T09:27:50+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[provided.al2023]": { - "last_validated_date": "2024-11-18T15:48:48+00:00" + "last_validated_date": "2024-11-26T09:30:57+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[provided.al2]": { - "last_validated_date": "2024-11-18T15:48:57+00:00" + "last_validated_date": "2024-11-26T09:31:05+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.10]": { - "last_validated_date": "2024-11-18T15:47:43+00:00" + "last_validated_date": "2024-11-26T09:28:18+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.11]": { - "last_validated_date": "2024-11-18T15:47:38+00:00" + "last_validated_date": "2024-11-26T09:28:14+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.12]": { - "last_validated_date": "2024-11-18T15:47:33+00:00" + "last_validated_date": "2024-11-26T09:28:10+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.13]": { - "last_validated_date": "2024-11-18T15:47:28+00:00" + "last_validated_date": "2024-11-26T09:28:06+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.8]": { - "last_validated_date": "2024-11-18T15:47:53+00:00" + "last_validated_date": "2024-11-26T09:28:27+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.9]": { - "last_validated_date": "2024-11-18T15:47:48+00:00" + "last_validated_date": "2024-11-26T09:28:22+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.2]": { - "last_validated_date": "2024-11-18T15:48:25+00:00" + "last_validated_date": "2024-11-26T09:29:22+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.3]": { - "last_validated_date": "2024-11-18T15:48:31+00:00" + "last_validated_date": "2024-11-26T09:29:26+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[dotnet6]": { - "last_validated_date": "2024-11-18T15:49:50+00:00" + "last_validated_date": "2024-11-26T09:32:01+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[dotnet8]": { - "last_validated_date": "2024-11-18T15:49:54+00:00" + "last_validated_date": "2024-11-26T09:32:13+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java11]": { - "last_validated_date": "2024-11-18T15:49:36+00:00" + "last_validated_date": "2024-11-26T09:31:43+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java17]": { - "last_validated_date": "2024-11-18T15:49:32+00:00" + "last_validated_date": "2024-11-26T09:31:40+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java21]": { - "last_validated_date": "2024-11-18T15:49:29+00:00" + "last_validated_date": "2024-11-26T09:31:38+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java8.al2]": { - "last_validated_date": "2024-11-18T15:49:40+00:00" + "last_validated_date": "2024-11-26T09:31:46+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs16.x]": { - "last_validated_date": "2024-11-18T15:49:06+00:00" + "last_validated_date": "2024-11-26T09:31:15+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs18.x]": { - "last_validated_date": "2024-11-18T15:49:03+00:00" + "last_validated_date": "2024-11-26T09:31:12+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs20.x]": { - "last_validated_date": "2024-11-18T15:49:00+00:00" + "last_validated_date": "2024-11-26T09:31:10+00:00" + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs22.x]": { + "last_validated_date": "2024-11-26T09:31:08+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[provided.al2023]": { - "last_validated_date": "2024-11-18T15:50:03+00:00" + "last_validated_date": "2024-11-26T09:33:24+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[provided.al2]": { - "last_validated_date": "2024-11-18T15:50:07+00:00" + "last_validated_date": "2024-11-26T09:33:29+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.10]": { - "last_validated_date": "2024-11-18T15:49:19+00:00" + "last_validated_date": "2024-11-26T09:31:24+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.11]": { - "last_validated_date": "2024-11-18T15:49:16+00:00" + "last_validated_date": "2024-11-26T09:31:22+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.12]": { - "last_validated_date": "2024-11-18T15:49:13+00:00" + "last_validated_date": "2024-11-26T09:31:20+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.13]": { - "last_validated_date": "2024-11-18T15:49:10+00:00" + "last_validated_date": "2024-11-26T09:31:17+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.8]": { - "last_validated_date": "2024-11-18T15:49:25+00:00" + "last_validated_date": "2024-11-26T09:31:28+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.9]": { - "last_validated_date": "2024-11-18T15:49:22+00:00" + "last_validated_date": "2024-11-26T09:31:26+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.2]": { - "last_validated_date": "2024-11-18T15:49:44+00:00" + "last_validated_date": "2024-11-26T09:31:49+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.3]": { - "last_validated_date": "2024-11-18T15:49:47+00:00" + "last_validated_date": "2024-11-26T09:31:51+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[dotnet6]": { - "last_validated_date": "2024-11-18T15:52:00+00:00" + "last_validated_date": "2024-11-26T09:35:40+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[dotnet8]": { - "last_validated_date": "2024-11-18T15:51:54+00:00" + "last_validated_date": "2024-11-26T09:35:15+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java11]": { - "last_validated_date": "2024-11-18T15:51:16+00:00" + "last_validated_date": "2024-11-26T09:35:22+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java17]": { - "last_validated_date": "2024-11-18T15:51:41+00:00" + "last_validated_date": "2024-11-26T09:35:45+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java21]": { - "last_validated_date": "2024-11-18T15:51:26+00:00" + "last_validated_date": "2024-11-26T09:35:29+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java8.al2]": { - "last_validated_date": "2024-11-18T15:51:48+00:00" + "last_validated_date": "2024-11-26T09:35:33+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs16.x]": { - "last_validated_date": "2024-11-18T15:51:32+00:00" + "last_validated_date": "2024-11-26T09:35:27+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs18.x]": { - "last_validated_date": "2024-11-18T15:51:35+00:00" + "last_validated_date": "2024-11-26T09:35:35+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs20.x]": { - "last_validated_date": "2024-11-18T15:51:22+00:00" + "last_validated_date": "2024-11-26T09:35:47+00:00" + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs22.x]": { + "last_validated_date": "2024-11-26T09:35:42+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.10]": { - "last_validated_date": "2024-11-18T15:51:44+00:00" + "last_validated_date": "2024-11-26T09:35:10+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.11]": { - "last_validated_date": "2024-11-18T15:51:10+00:00" + "last_validated_date": "2024-11-26T09:35:49+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.12]": { - "last_validated_date": "2024-11-18T15:51:29+00:00" + "last_validated_date": "2024-11-26T09:35:24+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.13]": { - "last_validated_date": "2024-11-18T15:51:38+00:00" + "last_validated_date": "2024-11-26T09:35:12+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.8]": { - "last_validated_date": "2024-11-18T15:51:19+00:00" + "last_validated_date": "2024-11-26T09:35:17+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.9]": { - "last_validated_date": "2024-11-18T15:51:13+00:00" + "last_validated_date": "2024-11-26T09:35:37+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.2]": { - "last_validated_date": "2024-11-18T15:51:51+00:00" + "last_validated_date": "2024-11-26T09:35:20+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.3]": { - "last_validated_date": "2024-11-18T15:51:57+00:00" + "last_validated_date": "2024-11-26T09:35:08+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[dotnet6]": { - "last_validated_date": "2024-11-18T15:50:56+00:00" + "last_validated_date": "2024-11-26T09:34:21+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[dotnet8]": { - "last_validated_date": "2024-11-18T15:50:59+00:00" + "last_validated_date": "2024-11-26T09:34:30+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java11]": { - "last_validated_date": "2024-11-18T15:50:43+00:00" + "last_validated_date": "2024-11-26T09:34:06+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java17]": { - "last_validated_date": "2024-11-18T15:50:39+00:00" + "last_validated_date": "2024-11-26T09:34:03+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java21]": { - "last_validated_date": "2024-11-18T15:50:36+00:00" + "last_validated_date": "2024-11-26T09:34:00+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java8.al2]": { - "last_validated_date": "2024-11-18T15:50:47+00:00" + "last_validated_date": "2024-11-26T09:34:09+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs16.x]": { - "last_validated_date": "2024-11-18T15:50:16+00:00" + "last_validated_date": "2024-11-26T09:33:37+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs18.x]": { - "last_validated_date": "2024-11-18T15:50:13+00:00" + "last_validated_date": "2024-11-26T09:33:35+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs20.x]": { - "last_validated_date": "2024-11-18T15:50:10+00:00" + "last_validated_date": "2024-11-26T09:33:33+00:00" + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs22.x]": { + "last_validated_date": "2024-11-26T09:33:31+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[provided.al2023]": { - "last_validated_date": "2024-11-18T15:51:03+00:00" + "last_validated_date": "2024-11-26T09:35:00+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[provided.al2]": { - "last_validated_date": "2024-11-18T15:51:07+00:00" + "last_validated_date": "2024-11-26T09:35:05+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.10]": { - "last_validated_date": "2024-11-18T15:50:27+00:00" + "last_validated_date": "2024-11-26T09:33:46+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.11]": { - "last_validated_date": "2024-11-18T15:50:24+00:00" + "last_validated_date": "2024-11-26T09:33:44+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.12]": { - "last_validated_date": "2024-11-18T15:50:22+00:00" + "last_validated_date": "2024-11-26T09:33:42+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.13]": { - "last_validated_date": "2024-11-18T15:50:19+00:00" + "last_validated_date": "2024-11-26T09:33:40+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.8]": { - "last_validated_date": "2024-11-18T15:50:33+00:00" + "last_validated_date": "2024-11-26T09:33:50+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.9]": { - "last_validated_date": "2024-11-18T15:50:30+00:00" + "last_validated_date": "2024-11-26T09:33:48+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.2]": { - "last_validated_date": "2024-11-18T15:50:50+00:00" + "last_validated_date": "2024-11-26T09:34:11+00:00" }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.3]": { - "last_validated_date": "2024-11-18T15:50:53+00:00" + "last_validated_date": "2024-11-26T09:34:13+00:00" } } diff --git a/tests/aws/services/lambda_/test_lambda_runtimes.snapshot.json b/tests/aws/services/lambda_/test_lambda_runtimes.snapshot.json index 007faee4f043a..248a31729f39f 100644 --- a/tests/aws/services/lambda_/test_lambda_runtimes.snapshot.json +++ b/tests/aws/services/lambda_/test_lambda_runtimes.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs20.x]": { - "recorded-date": "13-03-2024, 08:54:28", + "recorded-date": "26-11-2024, 09:42:35", "recorded-content": { "creation-result": { "CreateEventSourceMappingResponse": null, @@ -66,7 +66,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs18.x]": { - "recorded-date": "13-03-2024, 08:54:34", + "recorded-date": "26-11-2024, 09:42:45", "recorded-content": { "creation-result": { "CreateEventSourceMappingResponse": null, @@ -132,7 +132,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs16.x]": { - "recorded-date": "13-03-2024, 08:54:44", + "recorded-date": "26-11-2024, 09:42:54", "recorded-content": { "creation-result": { "CreateEventSourceMappingResponse": null, @@ -198,7 +198,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_runtime_with_lib": { - "recorded-date": "13-03-2024, 08:55:00", + "recorded-date": "26-11-2024, 09:43:08", "recorded-content": { "create-result-jar-with-lib": { "CreateEventSourceMappingResponse": null, @@ -377,7 +377,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java21]": { - "recorded-date": "13-03-2024, 08:55:03", + "recorded-date": "26-11-2024, 09:43:11", "recorded-content": { "invoke_result": { "ExecutedVersion": "$LATEST", @@ -391,7 +391,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java17]": { - "recorded-date": "13-03-2024, 08:55:06", + "recorded-date": "26-11-2024, 09:43:14", "recorded-content": { "invoke_result": { "ExecutedVersion": "$LATEST", @@ -405,7 +405,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java11]": { - "recorded-date": "13-03-2024, 08:55:10", + "recorded-date": "26-11-2024, 09:43:17", "recorded-content": { "invoke_result": { "ExecutedVersion": "$LATEST", @@ -419,7 +419,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java8.al2]": { - "recorded-date": "13-03-2024, 08:55:13", + "recorded-date": "26-11-2024, 09:43:20", "recorded-content": { "invoke_result": { "ExecutedVersion": "$LATEST", @@ -433,7 +433,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java21]": { - "recorded-date": "13-03-2024, 08:55:20", + "recorded-date": "26-11-2024, 09:43:37", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -500,7 +500,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java17]": { - "recorded-date": "13-03-2024, 08:55:25", + "recorded-date": "26-11-2024, 09:43:52", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -567,7 +567,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java11]": { - "recorded-date": "13-03-2024, 08:55:31", + "recorded-date": "26-11-2024, 09:44:07", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -634,7 +634,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java8.al2]": { - "recorded-date": "13-03-2024, 08:55:36", + "recorded-date": "26-11-2024, 09:44:22", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -701,7 +701,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom::handleRequestCustom-CUSTOM]": { - "recorded-date": "13-03-2024, 08:55:45", + "recorded-date": "26-11-2024, 09:44:29", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -764,7 +764,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom-INTERFACE]": { - "recorded-date": "13-03-2024, 08:55:54", + "recorded-date": "26-11-2024, 09:44:39", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -827,7 +827,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom::handleRequest-INTERFACE]": { - "recorded-date": "13-03-2024, 08:56:01", + "recorded-date": "26-11-2024, 09:44:50", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -890,7 +890,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_lambda_subscribe_sns_topic": { - "recorded-date": "13-03-2024, 08:56:26", + "recorded-date": "26-11-2024, 09:45:22", "recorded-content": { "get-function": { "Code": { @@ -966,47 +966,47 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.12]": { - "recorded-date": "18-11-2024, 16:39:19", + "recorded-date": "26-11-2024, 09:45:27", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.11]": { - "recorded-date": "18-11-2024, 16:39:22", + "recorded-date": "26-11-2024, 09:45:30", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.10]": { - "recorded-date": "18-11-2024, 16:39:26", + "recorded-date": "26-11-2024, 09:45:32", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.9]": { - "recorded-date": "18-11-2024, 16:39:30", + "recorded-date": "26-11-2024, 09:45:35", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.8]": { - "recorded-date": "18-11-2024, 16:39:34", + "recorded-date": "26-11-2024, 09:45:38", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.12]": { - "recorded-date": "18-11-2024, 16:39:41", + "recorded-date": "26-11-2024, 09:45:42", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.11]": { - "recorded-date": "18-11-2024, 16:39:45", + "recorded-date": "26-11-2024, 09:45:45", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.10]": { - "recorded-date": "18-11-2024, 16:39:48", + "recorded-date": "26-11-2024, 09:45:47", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.9]": { - "recorded-date": "18-11-2024, 16:39:52", + "recorded-date": "26-11-2024, 09:45:49", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.8]": { - "recorded-date": "18-11-2024, 16:39:55", + "recorded-date": "26-11-2024, 09:45:51", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_uncaught_exception_invoke[provided.al2023]": { - "recorded-date": "14-03-2024, 17:15:53", + "recorded-date": "26-11-2024, 09:46:26", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1067,7 +1067,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_uncaught_exception_invoke[provided.al2]": { - "recorded-date": "14-03-2024, 17:15:56", + "recorded-date": "26-11-2024, 09:46:32", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1128,19 +1128,85 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_manual_endpoint_injection[provided.al2023]": { - "recorded-date": "14-03-2024, 17:19:05", + "recorded-date": "26-11-2024, 09:46:59", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_manual_endpoint_injection[provided.al2]": { - "recorded-date": "14-03-2024, 17:19:10", + "recorded-date": "26-11-2024, 09:47:11", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.13]": { - "recorded-date": "18-11-2024, 16:39:15", + "recorded-date": "26-11-2024, 09:45:25", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.13]": { - "recorded-date": "18-11-2024, 16:39:38", + "recorded-date": "26-11-2024, 09:45:40", "recorded-content": {} + }, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs22.x]": { + "recorded-date": "26-11-2024, 09:42:29", + "recorded-content": { + "creation-result": { + "CreateEventSourceMappingResponse": null, + "CreateFunctionResponse": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "<:1>", + "CodeSize": "", + "Description": "", + "Environment": { + "Variables": {} + }, + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "lambda_handler_es6.handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 128, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "nodejs22.x", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 30, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + } + }, + "invocation-result": { + "ExecutedVersion": "$LATEST", + "Payload": { + "statusCode": 200, + "body": "\"response from localstack lambda: {\\\"event_type\\\":\\\"test_lambda\\\"}\"" + }, + "StatusCode": 200, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/lambda_/test_lambda_runtimes.validation.json b/tests/aws/services/lambda_/test_lambda_runtimes.validation.json index ac6fc381dd0e8..0b47eb2edb90c 100644 --- a/tests/aws/services/lambda_/test_lambda_runtimes.validation.json +++ b/tests/aws/services/lambda_/test_lambda_runtimes.validation.json @@ -1,98 +1,101 @@ { "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_manual_endpoint_injection[provided.al2023]": { - "last_validated_date": "2024-03-14T17:19:04+00:00" + "last_validated_date": "2024-11-26T09:46:59+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_manual_endpoint_injection[provided.al2]": { - "last_validated_date": "2024-03-14T17:19:09+00:00" + "last_validated_date": "2024-11-26T09:47:11+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_uncaught_exception_invoke[provided.al2023]": { - "last_validated_date": "2024-03-14T17:15:53+00:00" + "last_validated_date": "2024-11-26T09:46:26+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_uncaught_exception_invoke[provided.al2]": { - "last_validated_date": "2024-03-14T17:15:56+00:00" + "last_validated_date": "2024-11-26T09:46:31+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom-INTERFACE]": { - "last_validated_date": "2024-03-13T08:55:53+00:00" + "last_validated_date": "2024-11-26T09:44:39+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom::handleRequest-INTERFACE]": { - "last_validated_date": "2024-03-13T08:56:01+00:00" + "last_validated_date": "2024-11-26T09:44:50+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom::handleRequestCustom-CUSTOM]": { - "last_validated_date": "2024-03-13T08:55:45+00:00" + "last_validated_date": "2024-11-26T09:44:29+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_lambda_subscribe_sns_topic": { - "last_validated_date": "2024-03-13T08:56:24+00:00" + "last_validated_date": "2024-11-26T09:45:21+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_runtime_with_lib": { - "last_validated_date": "2024-03-13T08:54:58+00:00" + "last_validated_date": "2024-11-26T09:43:07+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java11]": { - "last_validated_date": "2024-03-13T08:55:30+00:00" + "last_validated_date": "2024-11-26T09:44:07+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java17]": { - "last_validated_date": "2024-03-13T08:55:24+00:00" + "last_validated_date": "2024-11-26T09:43:52+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java21]": { - "last_validated_date": "2024-03-13T08:55:19+00:00" + "last_validated_date": "2024-11-26T09:43:37+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java8.al2]": { - "last_validated_date": "2024-03-13T08:55:36+00:00" + "last_validated_date": "2024-11-26T09:44:22+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java11]": { - "last_validated_date": "2024-03-13T08:55:09+00:00" + "last_validated_date": "2024-11-26T09:43:16+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java17]": { - "last_validated_date": "2024-03-13T08:55:05+00:00" + "last_validated_date": "2024-11-26T09:43:13+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java21]": { - "last_validated_date": "2024-03-13T08:55:03+00:00" + "last_validated_date": "2024-11-26T09:43:11+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java8.al2]": { - "last_validated_date": "2024-03-13T08:55:12+00:00" + "last_validated_date": "2024-11-26T09:43:19+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs16.x]": { - "last_validated_date": "2024-03-13T08:54:44+00:00" + "last_validated_date": "2024-11-26T09:42:54+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs18.x]": { - "last_validated_date": "2024-03-13T08:54:33+00:00" + "last_validated_date": "2024-11-26T09:42:44+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs20.x]": { - "last_validated_date": "2024-03-13T08:54:27+00:00" + "last_validated_date": "2024-11-26T09:42:35+00:00" + }, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs22.x]": { + "last_validated_date": "2024-11-26T09:42:29+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.10]": { - "last_validated_date": "2024-11-18T16:39:25+00:00" + "last_validated_date": "2024-11-26T09:45:32+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.11]": { - "last_validated_date": "2024-11-18T16:39:21+00:00" + "last_validated_date": "2024-11-26T09:45:29+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.12]": { - "last_validated_date": "2024-11-18T16:39:18+00:00" + "last_validated_date": "2024-11-26T09:45:27+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.13]": { - "last_validated_date": "2024-11-18T16:39:14+00:00" + "last_validated_date": "2024-11-26T09:45:24+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.8]": { - "last_validated_date": "2024-11-18T16:39:33+00:00" + "last_validated_date": "2024-11-26T09:45:37+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.9]": { - "last_validated_date": "2024-11-18T16:39:29+00:00" + "last_validated_date": "2024-11-26T09:45:35+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.10]": { - "last_validated_date": "2024-11-18T16:39:47+00:00" + "last_validated_date": "2024-11-26T09:45:47+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.11]": { - "last_validated_date": "2024-11-18T16:39:44+00:00" + "last_validated_date": "2024-11-26T09:45:44+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.12]": { - "last_validated_date": "2024-11-18T16:39:40+00:00" + "last_validated_date": "2024-11-26T09:45:42+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.13]": { - "last_validated_date": "2024-11-18T16:39:37+00:00" + "last_validated_date": "2024-11-26T09:45:40+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.8]": { - "last_validated_date": "2024-11-18T16:39:54+00:00" + "last_validated_date": "2024-11-26T09:45:51+00:00" }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.9]": { - "last_validated_date": "2024-11-18T16:39:51+00:00" + "last_validated_date": "2024-11-26T09:45:49+00:00" } } From 95210a826a4118ecf1fd7b0168730266a9d07e9e Mon Sep 17 00:00:00 2001 From: Ben Simon Hartung <42031100+bentsku@users.noreply.github.com> Date: Tue, 26 Nov 2024 17:16:16 +0100 Subject: [PATCH 09/38] update rolo to 0.7.4 (#11933) --- requirements-base-runtime.txt | 2 +- requirements-dev.txt | 2 +- requirements-runtime.txt | 2 +- requirements-test.txt | 2 +- requirements-typehint.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/requirements-base-runtime.txt b/requirements-base-runtime.txt index b20d607bee59d..d9ed46c27701c 100644 --- a/requirements-base-runtime.txt +++ b/requirements-base-runtime.txt @@ -164,7 +164,7 @@ rfc3339-validator==0.1.4 # via openapi-schema-validator rich==13.9.4 # via localstack-core (pyproject.toml) -rolo==0.7.3 +rolo==0.7.4 # via localstack-core (pyproject.toml) rpds-py==0.21.0 # via diff --git a/requirements-dev.txt b/requirements-dev.txt index 6e0f93a244d3a..27f505b6fde72 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -423,7 +423,7 @@ rich==13.9.4 # via # localstack-core # localstack-core (pyproject.toml) -rolo==0.7.3 +rolo==0.7.4 # via localstack-core rpds-py==0.21.0 # via diff --git a/requirements-runtime.txt b/requirements-runtime.txt index 9a0ffb8826e1c..1dab31c0cbbfd 100644 --- a/requirements-runtime.txt +++ b/requirements-runtime.txt @@ -307,7 +307,7 @@ rich==13.9.4 # via # localstack-core # localstack-core (pyproject.toml) -rolo==0.7.3 +rolo==0.7.4 # via localstack-core rpds-py==0.21.0 # via diff --git a/requirements-test.txt b/requirements-test.txt index a2d621b7c0a8f..7a4029a29be60 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -389,7 +389,7 @@ rich==13.9.4 # via # localstack-core # localstack-core (pyproject.toml) -rolo==0.7.3 +rolo==0.7.4 # via localstack-core rpds-py==0.21.0 # via diff --git a/requirements-typehint.txt b/requirements-typehint.txt index 0c51d6db60ef0..c20ecfe99a4b9 100644 --- a/requirements-typehint.txt +++ b/requirements-typehint.txt @@ -621,7 +621,7 @@ rich==13.9.4 # via # localstack-core # localstack-core (pyproject.toml) -rolo==0.7.3 +rolo==0.7.4 # via localstack-core rpds-py==0.21.0 # via From 1abd2ff9f5e72254f22d956717723140225ab94a Mon Sep 17 00:00:00 2001 From: Dominik Schubert Date: Tue, 26 Nov 2024 17:52:14 +0100 Subject: [PATCH 10/38] Remove custom spec for AWS StepFunctions (#11925) --- .../stepfunctions/2016-11-23/service-2.json | 4160 ----------------- 1 file changed, 4160 deletions(-) delete mode 100644 localstack-core/localstack/aws/data/stepfunctions/2016-11-23/service-2.json diff --git a/localstack-core/localstack/aws/data/stepfunctions/2016-11-23/service-2.json b/localstack-core/localstack/aws/data/stepfunctions/2016-11-23/service-2.json deleted file mode 100644 index 0e9107c65589c..0000000000000 --- a/localstack-core/localstack/aws/data/stepfunctions/2016-11-23/service-2.json +++ /dev/null @@ -1,4160 +0,0 @@ -{ - "version":"2.0", - "metadata":{ - "apiVersion":"2016-11-23", - "endpointPrefix":"states", - "jsonVersion":"1.0", - "protocol":"json", - "protocols":["json"], - "serviceAbbreviation":"AWS SFN", - "serviceFullName":"AWS Step Functions", - "serviceId":"SFN", - "signatureVersion":"v4", - "targetPrefix":"AWSStepFunctions", - "uid":"states-2016-11-23", - "auth":["aws.auth#sigv4"] - }, - "operations":{ - "CreateActivity":{ - "name":"CreateActivity", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"CreateActivityInput"}, - "output":{"shape":"CreateActivityOutput"}, - "errors":[ - {"shape":"ActivityLimitExceeded"}, - {"shape":"ActivityAlreadyExists"}, - {"shape":"InvalidName"}, - {"shape":"TooManyTags"}, - {"shape":"InvalidEncryptionConfiguration"}, - {"shape":"KmsAccessDeniedException"}, - {"shape":"KmsThrottlingException"} - ], - "documentation":"

Creates an activity. An activity is a task that you write in any programming language and host on any machine that has access to Step Functions. Activities must poll Step Functions using the GetActivityTask API action and respond using SendTask* API actions. This function lets Step Functions know the existence of your activity and returns an identifier for use in a state machine and when polling from the activity.

This operation is eventually consistent. The results are best effort and may not reflect very recent updates and changes.

CreateActivity is an idempotent API. Subsequent requests won’t create a duplicate resource if it was already created. CreateActivity's idempotency check is based on the activity name. If a following request has different tags values, Step Functions will ignore these differences and treat it as an idempotent request of the previous. In this case, tags will not be updated, even if they are different.

", - "idempotent":true - }, - "CreateStateMachine":{ - "name":"CreateStateMachine", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"CreateStateMachineInput"}, - "output":{"shape":"CreateStateMachineOutput"}, - "errors":[ - {"shape":"InvalidArn"}, - {"shape":"InvalidDefinition"}, - {"shape":"InvalidName"}, - {"shape":"InvalidLoggingConfiguration"}, - {"shape":"InvalidTracingConfiguration"}, - {"shape":"StateMachineAlreadyExists"}, - {"shape":"StateMachineDeleting"}, - {"shape":"StateMachineLimitExceeded"}, - {"shape":"StateMachineTypeNotSupported"}, - {"shape":"TooManyTags"}, - {"shape":"ValidationException"}, - {"shape":"ConflictException"}, - {"shape":"InvalidEncryptionConfiguration"}, - {"shape":"KmsAccessDeniedException"}, - {"shape":"KmsThrottlingException"} - ], - "documentation":"

Creates a state machine. A state machine consists of a collection of states that can do work (Task states), determine to which states to transition next (Choice states), stop an execution with an error (Fail states), and so on. State machines are specified using a JSON-based, structured language. For more information, see Amazon States Language in the Step Functions User Guide.

If you set the publish parameter of this API action to true, it publishes version 1 as the first revision of the state machine.

For additional control over security, you can encrypt your data using a customer-managed key for Step Functions state machines. You can configure a symmetric KMS key and data key reuse period when creating or updating a State Machine. The execution history and state machine definition will be encrypted with the key applied to the State Machine.

This operation is eventually consistent. The results are best effort and may not reflect very recent updates and changes.

CreateStateMachine is an idempotent API. Subsequent requests won’t create a duplicate resource if it was already created. CreateStateMachine's idempotency check is based on the state machine name, definition, type, LoggingConfiguration, TracingConfiguration, and EncryptionConfiguration The check is also based on the publish and versionDescription parameters. If a following request has a different roleArn or tags, Step Functions will ignore these differences and treat it as an idempotent request of the previous. In this case, roleArn and tags will not be updated, even if they are different.

", - "idempotent":true - }, - "CreateStateMachineAlias":{ - "name":"CreateStateMachineAlias", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"CreateStateMachineAliasInput"}, - "output":{"shape":"CreateStateMachineAliasOutput"}, - "errors":[ - {"shape":"InvalidArn"}, - {"shape":"InvalidName"}, - {"shape":"ValidationException"}, - {"shape":"StateMachineDeleting"}, - {"shape":"ResourceNotFound"}, - {"shape":"ConflictException"}, - {"shape":"ServiceQuotaExceededException"} - ], - "documentation":"

Creates an alias for a state machine that points to one or two versions of the same state machine. You can set your application to call StartExecution with an alias and update the version the alias uses without changing the client's code.

You can also map an alias to split StartExecution requests between two versions of a state machine. To do this, add a second RoutingConfig object in the routingConfiguration parameter. You must also specify the percentage of execution run requests each version should receive in both RoutingConfig objects. Step Functions randomly chooses which version runs a given execution based on the percentage you specify.

To create an alias that points to a single version, specify a single RoutingConfig object with a weight set to 100.

You can create up to 100 aliases for each state machine. You must delete unused aliases using the DeleteStateMachineAlias API action.

CreateStateMachineAlias is an idempotent API. Step Functions bases the idempotency check on the stateMachineArn, description, name, and routingConfiguration parameters. Requests that contain the same values for these parameters return a successful idempotent response without creating a duplicate resource.

Related operations:

" - }, - "DeleteActivity":{ - "name":"DeleteActivity", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DeleteActivityInput"}, - "output":{"shape":"DeleteActivityOutput"}, - "errors":[ - {"shape":"InvalidArn"} - ], - "documentation":"

Deletes an activity.

" - }, - "DeleteStateMachine":{ - "name":"DeleteStateMachine", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DeleteStateMachineInput"}, - "output":{"shape":"DeleteStateMachineOutput"}, - "errors":[ - {"shape":"InvalidArn"}, - {"shape":"ValidationException"} - ], - "documentation":"

Deletes a state machine. This is an asynchronous operation. It sets the state machine's status to DELETING and begins the deletion process. A state machine is deleted only when all its executions are completed. On the next state transition, the state machine's executions are terminated.

A qualified state machine ARN can either refer to a Distributed Map state defined within a state machine, a version ARN, or an alias ARN.

The following are some examples of qualified and unqualified state machine ARNs:

  • The following qualified state machine ARN refers to a Distributed Map state with a label mapStateLabel in a state machine named myStateMachine.

    arn:partition:states:region:account-id:stateMachine:myStateMachine/mapStateLabel

    If you provide a qualified state machine ARN that refers to a Distributed Map state, the request fails with ValidationException.

  • The following unqualified state machine ARN refers to a state machine named myStateMachine.

    arn:partition:states:region:account-id:stateMachine:myStateMachine

This API action also deletes all versions and aliases associated with a state machine.

For EXPRESS state machines, the deletion happens eventually (usually in less than a minute). Running executions may emit logs after DeleteStateMachine API is called.

" - }, - "DeleteStateMachineAlias":{ - "name":"DeleteStateMachineAlias", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DeleteStateMachineAliasInput"}, - "output":{"shape":"DeleteStateMachineAliasOutput"}, - "errors":[ - {"shape":"ValidationException"}, - {"shape":"InvalidArn"}, - {"shape":"ResourceNotFound"}, - {"shape":"ConflictException"} - ], - "documentation":"

Deletes a state machine alias.

After you delete a state machine alias, you can't use it to start executions. When you delete a state machine alias, Step Functions doesn't delete the state machine versions that alias references.

Related operations:

" - }, - "DeleteStateMachineVersion":{ - "name":"DeleteStateMachineVersion", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DeleteStateMachineVersionInput"}, - "output":{"shape":"DeleteStateMachineVersionOutput"}, - "errors":[ - {"shape":"ValidationException"}, - {"shape":"InvalidArn"}, - {"shape":"ConflictException"} - ], - "documentation":"

Deletes a state machine version. After you delete a version, you can't call StartExecution using that version's ARN or use the version with a state machine alias.

Deleting a state machine version won't terminate its in-progress executions.

You can't delete a state machine version currently referenced by one or more aliases. Before you delete a version, you must either delete the aliases or update them to point to another state machine version.

Related operations:

" - }, - "DescribeActivity":{ - "name":"DescribeActivity", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DescribeActivityInput"}, - "output":{"shape":"DescribeActivityOutput"}, - "errors":[ - {"shape":"ActivityDoesNotExist"}, - {"shape":"InvalidArn"} - ], - "documentation":"

Describes an activity.

This operation is eventually consistent. The results are best effort and may not reflect very recent updates and changes.

" - }, - "DescribeExecution":{ - "name":"DescribeExecution", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DescribeExecutionInput"}, - "output":{"shape":"DescribeExecutionOutput"}, - "errors":[ - {"shape":"ExecutionDoesNotExist"}, - {"shape":"InvalidArn"}, - {"shape":"KmsAccessDeniedException"}, - {"shape":"KmsInvalidStateException"}, - {"shape":"KmsThrottlingException"} - ], - "documentation":"

Provides information about a state machine execution, such as the state machine associated with the execution, the execution input and output, and relevant execution metadata. If you've redriven an execution, you can use this API action to return information about the redrives of that execution. In addition, you can use this API action to return the Map Run Amazon Resource Name (ARN) if the execution was dispatched by a Map Run.

If you specify a version or alias ARN when you call the StartExecution API action, DescribeExecution returns that ARN.

This operation is eventually consistent. The results are best effort and may not reflect very recent updates and changes.

Executions of an EXPRESS state machine aren't supported by DescribeExecution unless a Map Run dispatched them.

" - }, - "DescribeMapRun":{ - "name":"DescribeMapRun", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DescribeMapRunInput"}, - "output":{"shape":"DescribeMapRunOutput"}, - "errors":[ - {"shape":"ResourceNotFound"}, - {"shape":"InvalidArn"} - ], - "documentation":"

Provides information about a Map Run's configuration, progress, and results. If you've redriven a Map Run, this API action also returns information about the redrives of that Map Run. For more information, see Examining Map Run in the Step Functions Developer Guide.

" - }, - "DescribeStateMachine":{ - "name":"DescribeStateMachine", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DescribeStateMachineInput"}, - "output":{"shape":"DescribeStateMachineOutput"}, - "errors":[ - {"shape":"InvalidArn"}, - {"shape":"StateMachineDoesNotExist"}, - {"shape":"KmsAccessDeniedException"}, - {"shape":"KmsInvalidStateException"}, - {"shape":"KmsThrottlingException"} - ], - "documentation":"

Provides information about a state machine's definition, its IAM role Amazon Resource Name (ARN), and configuration.

A qualified state machine ARN can either refer to a Distributed Map state defined within a state machine, a version ARN, or an alias ARN.

The following are some examples of qualified and unqualified state machine ARNs:

  • The following qualified state machine ARN refers to a Distributed Map state with a label mapStateLabel in a state machine named myStateMachine.

    arn:partition:states:region:account-id:stateMachine:myStateMachine/mapStateLabel

    If you provide a qualified state machine ARN that refers to a Distributed Map state, the request fails with ValidationException.

  • The following qualified state machine ARN refers to an alias named PROD.

    arn:<partition>:states:<region>:<account-id>:stateMachine:<myStateMachine:PROD>

    If you provide a qualified state machine ARN that refers to a version ARN or an alias ARN, the request starts execution for that version or alias.

  • The following unqualified state machine ARN refers to a state machine named myStateMachine.

    arn:<partition>:states:<region>:<account-id>:stateMachine:<myStateMachine>

This API action returns the details for a state machine version if the stateMachineArn you specify is a state machine version ARN.

This operation is eventually consistent. The results are best effort and may not reflect very recent updates and changes.

" - }, - "DescribeStateMachineAlias":{ - "name":"DescribeStateMachineAlias", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DescribeStateMachineAliasInput"}, - "output":{"shape":"DescribeStateMachineAliasOutput"}, - "errors":[ - {"shape":"ValidationException"}, - {"shape":"InvalidArn"}, - {"shape":"ResourceNotFound"} - ], - "documentation":"

Returns details about a state machine alias.

Related operations:

" - }, - "DescribeStateMachineForExecution":{ - "name":"DescribeStateMachineForExecution", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DescribeStateMachineForExecutionInput"}, - "output":{"shape":"DescribeStateMachineForExecutionOutput"}, - "errors":[ - {"shape":"ExecutionDoesNotExist"}, - {"shape":"InvalidArn"}, - {"shape":"KmsAccessDeniedException"}, - {"shape":"KmsInvalidStateException"}, - {"shape":"KmsThrottlingException"} - ], - "documentation":"

Provides information about a state machine's definition, its execution role ARN, and configuration. If a Map Run dispatched the execution, this action returns the Map Run Amazon Resource Name (ARN) in the response. The state machine returned is the state machine associated with the Map Run.

This operation is eventually consistent. The results are best effort and may not reflect very recent updates and changes.

This API action is not supported by EXPRESS state machines.

" - }, - "GetActivityTask":{ - "name":"GetActivityTask", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"GetActivityTaskInput"}, - "output":{"shape":"GetActivityTaskOutput"}, - "errors":[ - {"shape":"ActivityDoesNotExist"}, - {"shape":"ActivityWorkerLimitExceeded"}, - {"shape":"InvalidArn"}, - {"shape":"KmsAccessDeniedException"}, - {"shape":"KmsInvalidStateException"}, - {"shape":"KmsThrottlingException"} - ], - "documentation":"

Used by workers to retrieve a task (with the specified activity ARN) which has been scheduled for execution by a running state machine. This initiates a long poll, where the service holds the HTTP connection open and responds as soon as a task becomes available (i.e. an execution of a task of this type is needed.) The maximum time the service holds on to the request before responding is 60 seconds. If no task is available within 60 seconds, the poll returns a taskToken with a null string.

This API action isn't logged in CloudTrail.

Workers should set their client side socket timeout to at least 65 seconds (5 seconds higher than the maximum time the service may hold the poll request).

Polling with GetActivityTask can cause latency in some implementations. See Avoid Latency When Polling for Activity Tasks in the Step Functions Developer Guide.

" - }, - "GetExecutionHistory":{ - "name":"GetExecutionHistory", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"GetExecutionHistoryInput"}, - "output":{"shape":"GetExecutionHistoryOutput"}, - "errors":[ - {"shape":"ExecutionDoesNotExist"}, - {"shape":"InvalidArn"}, - {"shape":"InvalidToken"}, - {"shape":"KmsAccessDeniedException"}, - {"shape":"KmsInvalidStateException"}, - {"shape":"KmsThrottlingException"} - ], - "documentation":"

Returns the history of the specified execution as a list of events. By default, the results are returned in ascending order of the timeStamp of the events. Use the reverseOrder parameter to get the latest events first.

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

This API action is not supported by EXPRESS state machines.

" - }, - "ListActivities":{ - "name":"ListActivities", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListActivitiesInput"}, - "output":{"shape":"ListActivitiesOutput"}, - "errors":[ - {"shape":"InvalidToken"} - ], - "documentation":"

Lists the existing activities.

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

This operation is eventually consistent. The results are best effort and may not reflect very recent updates and changes.

" - }, - "ListExecutions":{ - "name":"ListExecutions", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListExecutionsInput"}, - "output":{"shape":"ListExecutionsOutput"}, - "errors":[ - {"shape":"InvalidArn"}, - {"shape":"InvalidToken"}, - {"shape":"StateMachineDoesNotExist"}, - {"shape":"StateMachineTypeNotSupported"}, - {"shape":"ValidationException"}, - {"shape":"ResourceNotFound"} - ], - "documentation":"

Lists all executions of a state machine or a Map Run. You can list all executions related to a state machine by specifying a state machine Amazon Resource Name (ARN), or those related to a Map Run by specifying a Map Run ARN. Using this API action, you can also list all redriven executions.

You can also provide a state machine alias ARN or version ARN to list the executions associated with a specific alias or version.

Results are sorted by time, with the most recent execution first.

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

This operation is eventually consistent. The results are best effort and may not reflect very recent updates and changes.

This API action is not supported by EXPRESS state machines.

" - }, - "ListMapRuns":{ - "name":"ListMapRuns", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListMapRunsInput"}, - "output":{"shape":"ListMapRunsOutput"}, - "errors":[ - {"shape":"ExecutionDoesNotExist"}, - {"shape":"InvalidArn"}, - {"shape":"InvalidToken"} - ], - "documentation":"

Lists all Map Runs that were started by a given state machine execution. Use this API action to obtain Map Run ARNs, and then call DescribeMapRun to obtain more information, if needed.

" - }, - "ListStateMachineAliases":{ - "name":"ListStateMachineAliases", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListStateMachineAliasesInput"}, - "output":{"shape":"ListStateMachineAliasesOutput"}, - "errors":[ - {"shape":"InvalidArn"}, - {"shape":"InvalidToken"}, - {"shape":"ResourceNotFound"}, - {"shape":"StateMachineDoesNotExist"}, - {"shape":"StateMachineDeleting"} - ], - "documentation":"

Lists aliases for a specified state machine ARN. Results are sorted by time, with the most recently created aliases listed first.

To list aliases that reference a state machine version, you can specify the version ARN in the stateMachineArn parameter.

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

Related operations:

" - }, - "ListStateMachineVersions":{ - "name":"ListStateMachineVersions", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListStateMachineVersionsInput"}, - "output":{"shape":"ListStateMachineVersionsOutput"}, - "errors":[ - {"shape":"ValidationException"}, - {"shape":"InvalidArn"}, - {"shape":"InvalidToken"} - ], - "documentation":"

Lists versions for the specified state machine Amazon Resource Name (ARN).

The results are sorted in descending order of the version creation time.

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

Related operations:

" - }, - "ListStateMachines":{ - "name":"ListStateMachines", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListStateMachinesInput"}, - "output":{"shape":"ListStateMachinesOutput"}, - "errors":[ - {"shape":"InvalidToken"} - ], - "documentation":"

Lists the existing state machines.

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

This operation is eventually consistent. The results are best effort and may not reflect very recent updates and changes.

" - }, - "ListTagsForResource":{ - "name":"ListTagsForResource", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListTagsForResourceInput"}, - "output":{"shape":"ListTagsForResourceOutput"}, - "errors":[ - {"shape":"InvalidArn"}, - {"shape":"ResourceNotFound"} - ], - "documentation":"

List tags for a given resource.

Tags may only contain Unicode letters, digits, white space, or these symbols: _ . : / = + - @.

" - }, - "PublishStateMachineVersion":{ - "name":"PublishStateMachineVersion", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"PublishStateMachineVersionInput"}, - "output":{"shape":"PublishStateMachineVersionOutput"}, - "errors":[ - {"shape":"ValidationException"}, - {"shape":"StateMachineDeleting"}, - {"shape":"StateMachineDoesNotExist"}, - {"shape":"ServiceQuotaExceededException"}, - {"shape":"ConflictException"}, - {"shape":"InvalidArn"} - ], - "documentation":"

Creates a version from the current revision of a state machine. Use versions to create immutable snapshots of your state machine. You can start executions from versions either directly or with an alias. To create an alias, use CreateStateMachineAlias.

You can publish up to 1000 versions for each state machine. You must manually delete unused versions using the DeleteStateMachineVersion API action.

PublishStateMachineVersion is an idempotent API. It doesn't create a duplicate state machine version if it already exists for the current revision. Step Functions bases PublishStateMachineVersion's idempotency check on the stateMachineArn, name, and revisionId parameters. Requests with the same parameters return a successful idempotent response. If you don't specify a revisionId, Step Functions checks for a previously published version of the state machine's current revision.

Related operations:

", - "idempotent":true - }, - "RedriveExecution":{ - "name":"RedriveExecution", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"RedriveExecutionInput"}, - "output":{"shape":"RedriveExecutionOutput"}, - "errors":[ - {"shape":"ExecutionDoesNotExist"}, - {"shape":"ExecutionNotRedrivable"}, - {"shape":"ExecutionLimitExceeded"}, - {"shape":"InvalidArn"}, - {"shape":"ValidationException"} - ], - "documentation":"

Restarts unsuccessful executions of Standard workflows that didn't complete successfully in the last 14 days. These include failed, aborted, or timed out executions. When you redrive an execution, it continues the failed execution from the unsuccessful step and uses the same input. Step Functions preserves the results and execution history of the successful steps, and doesn't rerun these steps when you redrive an execution. Redriven executions use the same state machine definition and execution ARN as the original execution attempt.

For workflows that include an Inline Map or Parallel state, RedriveExecution API action reschedules and redrives only the iterations and branches that failed or aborted.

To redrive a workflow that includes a Distributed Map state whose Map Run failed, you must redrive the parent workflow. The parent workflow redrives all the unsuccessful states, including a failed Map Run. If a Map Run was not started in the original execution attempt, the redriven parent workflow starts the Map Run.

This API action is not supported by EXPRESS state machines.

However, you can restart the unsuccessful executions of Express child workflows in a Distributed Map by redriving its Map Run. When you redrive a Map Run, the Express child workflows are rerun using the StartExecution API action. For more information, see Redriving Map Runs.

You can redrive executions if your original execution meets the following conditions:

  • The execution status isn't SUCCEEDED.

  • Your workflow execution has not exceeded the redrivable period of 14 days. Redrivable period refers to the time during which you can redrive a given execution. This period starts from the day a state machine completes its execution.

  • The workflow execution has not exceeded the maximum open time of one year. For more information about state machine quotas, see Quotas related to state machine executions.

  • The execution event history count is less than 24,999. Redriven executions append their event history to the existing event history. Make sure your workflow execution contains less than 24,999 events to accommodate the ExecutionRedriven history event and at least one other history event.

", - "idempotent":true - }, - "SendTaskFailure":{ - "name":"SendTaskFailure", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"SendTaskFailureInput"}, - "output":{"shape":"SendTaskFailureOutput"}, - "errors":[ - {"shape":"TaskDoesNotExist"}, - {"shape":"InvalidToken"}, - {"shape":"TaskTimedOut"}, - {"shape":"KmsAccessDeniedException"}, - {"shape":"KmsInvalidStateException"}, - {"shape":"KmsThrottlingException"} - ], - "documentation":"

Used by activity workers, Task states using the callback pattern, and optionally Task states using the job run pattern to report that the task identified by the taskToken failed.

For an execution with encryption enabled, Step Functions will encrypt the error and cause fields using the KMS key for the execution role.

A caller can mark a task as fail without using any KMS permissions in the execution role if the caller provides a null value for both error and cause fields because no data needs to be encrypted.

" - }, - "SendTaskHeartbeat":{ - "name":"SendTaskHeartbeat", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"SendTaskHeartbeatInput"}, - "output":{"shape":"SendTaskHeartbeatOutput"}, - "errors":[ - {"shape":"TaskDoesNotExist"}, - {"shape":"InvalidToken"}, - {"shape":"TaskTimedOut"} - ], - "documentation":"

Used by activity workers and Task states using the callback pattern, and optionally Task states using the job run pattern to report to Step Functions that the task represented by the specified taskToken is still making progress. This action resets the Heartbeat clock. The Heartbeat threshold is specified in the state machine's Amazon States Language definition (HeartbeatSeconds). This action does not in itself create an event in the execution history. However, if the task times out, the execution history contains an ActivityTimedOut entry for activities, or a TaskTimedOut entry for tasks using the job run or callback pattern.

The Timeout of a task, defined in the state machine's Amazon States Language definition, is its maximum allowed duration, regardless of the number of SendTaskHeartbeat requests received. Use HeartbeatSeconds to configure the timeout interval for heartbeats.

" - }, - "SendTaskSuccess":{ - "name":"SendTaskSuccess", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"SendTaskSuccessInput"}, - "output":{"shape":"SendTaskSuccessOutput"}, - "errors":[ - {"shape":"TaskDoesNotExist"}, - {"shape":"InvalidOutput"}, - {"shape":"InvalidToken"}, - {"shape":"TaskTimedOut"}, - {"shape":"KmsAccessDeniedException"}, - {"shape":"KmsInvalidStateException"}, - {"shape":"KmsThrottlingException"} - ], - "documentation":"

Used by activity workers, Task states using the callback pattern, and optionally Task states using the job run pattern to report that the task identified by the taskToken completed successfully.

" - }, - "StartExecution":{ - "name":"StartExecution", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"StartExecutionInput"}, - "output":{"shape":"StartExecutionOutput"}, - "errors":[ - {"shape":"ExecutionLimitExceeded"}, - {"shape":"ExecutionAlreadyExists"}, - {"shape":"InvalidArn"}, - {"shape":"InvalidExecutionInput"}, - {"shape":"InvalidName"}, - {"shape":"StateMachineDoesNotExist"}, - {"shape":"StateMachineDeleting"}, - {"shape":"ValidationException"}, - {"shape":"KmsAccessDeniedException"}, - {"shape":"KmsInvalidStateException"}, - {"shape":"KmsThrottlingException"} - ], - "documentation":"

Starts a state machine execution.

A qualified state machine ARN can either refer to a Distributed Map state defined within a state machine, a version ARN, or an alias ARN.

The following are some examples of qualified and unqualified state machine ARNs:

  • The following qualified state machine ARN refers to a Distributed Map state with a label mapStateLabel in a state machine named myStateMachine.

    arn:partition:states:region:account-id:stateMachine:myStateMachine/mapStateLabel

    If you provide a qualified state machine ARN that refers to a Distributed Map state, the request fails with ValidationException.

  • The following qualified state machine ARN refers to an alias named PROD.

    arn:<partition>:states:<region>:<account-id>:stateMachine:<myStateMachine:PROD>

    If you provide a qualified state machine ARN that refers to a version ARN or an alias ARN, the request starts execution for that version or alias.

  • The following unqualified state machine ARN refers to a state machine named myStateMachine.

    arn:<partition>:states:<region>:<account-id>:stateMachine:<myStateMachine>

If you start an execution with an unqualified state machine ARN, Step Functions uses the latest revision of the state machine for the execution.

To start executions of a state machine version, call StartExecution and provide the version ARN or the ARN of an alias that points to the version.

StartExecution is idempotent for STANDARD workflows. For a STANDARD workflow, if you call StartExecution with the same name and input as a running execution, the call succeeds and return the same response as the original request. If the execution is closed or if the input is different, it returns a 400 ExecutionAlreadyExists error. You can reuse names after 90 days.

StartExecution isn't idempotent for EXPRESS workflows.

", - "idempotent":true - }, - "StartSyncExecution":{ - "name":"StartSyncExecution", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"StartSyncExecutionInput"}, - "output":{"shape":"StartSyncExecutionOutput"}, - "errors":[ - {"shape":"InvalidArn"}, - {"shape":"InvalidExecutionInput"}, - {"shape":"InvalidName"}, - {"shape":"StateMachineDoesNotExist"}, - {"shape":"StateMachineDeleting"}, - {"shape":"StateMachineTypeNotSupported"}, - {"shape":"KmsAccessDeniedException"}, - {"shape":"KmsInvalidStateException"}, - {"shape":"KmsThrottlingException"} - ], - "documentation":"

Starts a Synchronous Express state machine execution. StartSyncExecution is not available for STANDARD workflows.

StartSyncExecution will return a 200 OK response, even if your execution fails, because the status code in the API response doesn't reflect function errors. Error codes are reserved for errors that prevent your execution from running, such as permissions errors, limit errors, or issues with your state machine code and configuration.

This API action isn't logged in CloudTrail.

", - "endpoint":{"hostPrefix":"sync-"} - }, - "StopExecution":{ - "name":"StopExecution", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"StopExecutionInput"}, - "output":{"shape":"StopExecutionOutput"}, - "errors":[ - {"shape":"ExecutionDoesNotExist"}, - {"shape":"InvalidArn"}, - {"shape":"ValidationException"}, - {"shape":"KmsAccessDeniedException"}, - {"shape":"KmsInvalidStateException"}, - {"shape":"KmsThrottlingException"} - ], - "documentation":"

Stops an execution.

This API action is not supported by EXPRESS state machines.

For an execution with encryption enabled, Step Functions will encrypt the error and cause fields using the KMS key for the execution role.

A caller can stop an execution without using any KMS permissions in the execution role if the caller provides a null value for both error and cause fields because no data needs to be encrypted.

" - }, - "TagResource":{ - "name":"TagResource", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"TagResourceInput"}, - "output":{"shape":"TagResourceOutput"}, - "errors":[ - {"shape":"InvalidArn"}, - {"shape":"ResourceNotFound"}, - {"shape":"TooManyTags"} - ], - "documentation":"

Add a tag to a Step Functions resource.

An array of key-value pairs. For more information, see Using Cost Allocation Tags in the Amazon Web Services Billing and Cost Management User Guide, and Controlling Access Using IAM Tags.

Tags may only contain Unicode letters, digits, white space, or these symbols: _ . : / = + - @.

" - }, - "TestState":{ - "name":"TestState", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"TestStateInput"}, - "output":{"shape":"TestStateOutput"}, - "errors":[ - {"shape":"InvalidArn"}, - {"shape":"InvalidDefinition"}, - {"shape":"InvalidExecutionInput"}, - {"shape":"ValidationException"} - ], - "documentation":"

Accepts the definition of a single state and executes it. You can test a state without creating a state machine or updating an existing state machine. Using this API, you can test the following:

You can call this API on only one state at a time. The states that you can test include the following:

The TestState API assumes an IAM role which must contain the required IAM permissions for the resources your state is accessing. For information about the permissions a state might need, see IAM permissions to test a state.

The TestState API can run for up to five minutes. If the execution of a state exceeds this duration, it fails with the States.Timeout error.

TestState doesn't support Activity tasks, .sync or .waitForTaskToken service integration patterns, Parallel, or Map states.

", - "endpoint":{"hostPrefix":"sync-"} - }, - "UntagResource":{ - "name":"UntagResource", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"UntagResourceInput"}, - "output":{"shape":"UntagResourceOutput"}, - "errors":[ - {"shape":"InvalidArn"}, - {"shape":"ResourceNotFound"} - ], - "documentation":"

Remove a tag from a Step Functions resource

" - }, - "UpdateMapRun":{ - "name":"UpdateMapRun", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"UpdateMapRunInput"}, - "output":{"shape":"UpdateMapRunOutput"}, - "errors":[ - {"shape":"ResourceNotFound"}, - {"shape":"InvalidArn"}, - {"shape":"ValidationException"} - ], - "documentation":"

Updates an in-progress Map Run's configuration to include changes to the settings that control maximum concurrency and Map Run failure.

" - }, - "UpdateStateMachine":{ - "name":"UpdateStateMachine", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"UpdateStateMachineInput"}, - "output":{"shape":"UpdateStateMachineOutput"}, - "errors":[ - {"shape":"InvalidArn"}, - {"shape":"InvalidDefinition"}, - {"shape":"InvalidLoggingConfiguration"}, - {"shape":"InvalidTracingConfiguration"}, - {"shape":"MissingRequiredParameter"}, - {"shape":"StateMachineDeleting"}, - {"shape":"StateMachineDoesNotExist"}, - {"shape":"ServiceQuotaExceededException"}, - {"shape":"ConflictException"}, - {"shape":"ValidationException"}, - {"shape":"InvalidEncryptionConfiguration"}, - {"shape":"KmsAccessDeniedException"}, - {"shape":"KmsThrottlingException"} - ], - "documentation":"

Updates an existing state machine by modifying its definition, roleArn, loggingConfiguration, or EncryptionConfiguration. Running executions will continue to use the previous definition and roleArn. You must include at least one of definition or roleArn or you will receive a MissingRequiredParameter error.

A qualified state machine ARN refers to a Distributed Map state defined within a state machine. For example, the qualified state machine ARN arn:partition:states:region:account-id:stateMachine:stateMachineName/mapStateLabel refers to a Distributed Map state with a label mapStateLabel in the state machine named stateMachineName.

A qualified state machine ARN can either refer to a Distributed Map state defined within a state machine, a version ARN, or an alias ARN.

The following are some examples of qualified and unqualified state machine ARNs:

  • The following qualified state machine ARN refers to a Distributed Map state with a label mapStateLabel in a state machine named myStateMachine.

    arn:partition:states:region:account-id:stateMachine:myStateMachine/mapStateLabel

    If you provide a qualified state machine ARN that refers to a Distributed Map state, the request fails with ValidationException.

  • The following qualified state machine ARN refers to an alias named PROD.

    arn:<partition>:states:<region>:<account-id>:stateMachine:<myStateMachine:PROD>

    If you provide a qualified state machine ARN that refers to a version ARN or an alias ARN, the request starts execution for that version or alias.

  • The following unqualified state machine ARN refers to a state machine named myStateMachine.

    arn:<partition>:states:<region>:<account-id>:stateMachine:<myStateMachine>

After you update your state machine, you can set the publish parameter to true in the same action to publish a new version. This way, you can opt-in to strict versioning of your state machine.

Step Functions assigns monotonically increasing integers for state machine versions, starting at version number 1.

All StartExecution calls within a few seconds use the updated definition and roleArn. Executions started immediately after you call UpdateStateMachine may use the previous state machine definition and roleArn.

", - "idempotent":true - }, - "UpdateStateMachineAlias":{ - "name":"UpdateStateMachineAlias", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"UpdateStateMachineAliasInput"}, - "output":{"shape":"UpdateStateMachineAliasOutput"}, - "errors":[ - {"shape":"ValidationException"}, - {"shape":"InvalidArn"}, - {"shape":"ResourceNotFound"}, - {"shape":"ConflictException"}, - {"shape":"StateMachineDeleting"} - ], - "documentation":"

Updates the configuration of an existing state machine alias by modifying its description or routingConfiguration.

You must specify at least one of the description or routingConfiguration parameters to update a state machine alias.

UpdateStateMachineAlias is an idempotent API. Step Functions bases the idempotency check on the stateMachineAliasArn, description, and routingConfiguration parameters. Requests with the same parameters return an idempotent response.

This operation is eventually consistent. All StartExecution requests made within a few seconds use the latest alias configuration. Executions started immediately after calling UpdateStateMachineAlias may use the previous routing configuration.

Related operations:

" - }, - "ValidateStateMachineDefinition":{ - "name":"ValidateStateMachineDefinition", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ValidateStateMachineDefinitionInput"}, - "output":{"shape":"ValidateStateMachineDefinitionOutput"}, - "errors":[ - {"shape":"ValidationException"} - ], - "documentation":"

Validates the syntax of a state machine definition specified in Amazon States Language (ASL), a JSON-based, structured language.

You can validate that a state machine definition is correct without creating a state machine resource.

Suggested uses for ValidateStateMachineDefinition:

  • Integrate automated checks into your code review or Continuous Integration (CI) process to check state machine definitions before starting deployments.

  • Run validation from a Git pre-commit hook to verify the definition before committing to your source repository.

Validation will look for problems in your state machine definition and return a result and a list of diagnostic elements.

The result value will be OK when your workflow definition can be successfully created or updated. Note the result can be OK even when diagnostic warnings are present in the response. The result value will be FAIL when the workflow definition contains errors that would prevent you from creating or updating your state machine.

The list of ValidateStateMachineDefinitionDiagnostic data elements can contain zero or more WARNING and/or ERROR elements.

The ValidateStateMachineDefinition API might add new diagnostics in the future, adjust diagnostic codes, or change the message wording. Your automated processes should only rely on the value of the result field value (OK, FAIL). Do not rely on the exact order, count, or wording of diagnostic messages.

" - } - }, - "shapes":{ - "ActivityAlreadyExists":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

Activity already exists. EncryptionConfiguration may not be updated.

", - "exception":true - }, - "ActivityDoesNotExist":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The specified activity does not exist.

", - "exception":true - }, - "ActivityFailedEventDetails":{ - "type":"structure", - "members":{ - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - } - }, - "documentation":"

Contains details about an activity that failed during an execution.

" - }, - "ActivityLimitExceeded":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The maximum number of activities has been reached. Existing activities must be deleted before a new activity can be created.

", - "exception":true - }, - "ActivityList":{ - "type":"list", - "member":{"shape":"ActivityListItem"} - }, - "ActivityListItem":{ - "type":"structure", - "required":[ - "activityArn", - "name", - "creationDate" - ], - "members":{ - "activityArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies the activity.

" - }, - "name":{ - "shape":"Name", - "documentation":"

The name of the activity.

A name must not contain:

  • white space

  • brackets < > { } [ ]

  • wildcard characters ? *

  • special characters \" # % \\ ^ | ~ ` $ & , ; : /

  • control characters (U+0000-001F, U+007F-009F)

To enable logging with CloudWatch Logs, the name should only contain 0-9, A-Z, a-z, - and _.

" - }, - "creationDate":{ - "shape":"Timestamp", - "documentation":"

The date the activity is created.

" - } - }, - "documentation":"

Contains details about an activity.

" - }, - "ActivityScheduleFailedEventDetails":{ - "type":"structure", - "members":{ - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - } - }, - "documentation":"

Contains details about an activity schedule failure that occurred during an execution.

" - }, - "ActivityScheduledEventDetails":{ - "type":"structure", - "required":["resource"], - "members":{ - "resource":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the scheduled activity.

" - }, - "input":{ - "shape":"SensitiveData", - "documentation":"

The JSON data input to the activity task. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "inputDetails":{ - "shape":"HistoryEventExecutionDataDetails", - "documentation":"

Contains details about the input for an execution history event.

" - }, - "timeoutInSeconds":{ - "shape":"TimeoutInSeconds", - "documentation":"

The maximum allowed duration of the activity task.

", - "box":true - }, - "heartbeatInSeconds":{ - "shape":"TimeoutInSeconds", - "documentation":"

The maximum allowed duration between two heartbeats for the activity task.

", - "box":true - } - }, - "documentation":"

Contains details about an activity scheduled during an execution.

" - }, - "ActivityStartedEventDetails":{ - "type":"structure", - "members":{ - "workerName":{ - "shape":"Identity", - "documentation":"

The name of the worker that the task is assigned to. These names are provided by the workers when calling GetActivityTask.

" - } - }, - "documentation":"

Contains details about the start of an activity during an execution.

" - }, - "ActivitySucceededEventDetails":{ - "type":"structure", - "members":{ - "output":{ - "shape":"SensitiveData", - "documentation":"

The JSON data output by the activity task. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "outputDetails":{ - "shape":"HistoryEventExecutionDataDetails", - "documentation":"

Contains details about the output of an execution history event.

" - } - }, - "documentation":"

Contains details about an activity that successfully terminated during an execution.

" - }, - "ActivityTimedOutEventDetails":{ - "type":"structure", - "members":{ - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the timeout.

" - } - }, - "documentation":"

Contains details about an activity timeout that occurred during an execution.

" - }, - "ActivityWorkerLimitExceeded":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The maximum number of workers concurrently polling for activity tasks has been reached.

", - "exception":true - }, - "AliasDescription":{ - "type":"string", - "max":256, - "sensitive":true - }, - "Arn":{ - "type":"string", - "max":256, - "min":1 - }, - "AssignedVariables":{ - "type":"map", - "key":{"shape":"VariableName"}, - "value":{"shape":"VariableValue"} - }, - "AssignedVariablesDetails":{ - "type":"structure", - "members":{ - "truncated":{ - "shape":"truncated", - "documentation":"

Indicates whether assigned variables were truncated in the response. Always false for API calls. In CloudWatch logs, the value will be true if the data is truncated due to size limits.

" - } - }, - "documentation":"

Provides details about assigned variables in an execution history event.

" - }, - "BilledDuration":{ - "type":"long", - "min":0 - }, - "BilledMemoryUsed":{ - "type":"long", - "min":0 - }, - "BillingDetails":{ - "type":"structure", - "members":{ - "billedMemoryUsedInMB":{ - "shape":"BilledMemoryUsed", - "documentation":"

Billed memory consumption of your workflow, in MB.

" - }, - "billedDurationInMilliseconds":{ - "shape":"BilledDuration", - "documentation":"

Billed duration of your workflow, in milliseconds.

" - } - }, - "documentation":"

An object that describes workflow billing details.

" - }, - "CharacterRestrictedName":{ - "type":"string", - "max":80, - "min":1, - "pattern":"^(?=.*[a-zA-Z_\\-\\.])[a-zA-Z0-9_\\-\\.]+$" - }, - "ClientToken":{ - "type":"string", - "max":64, - "min":1, - "pattern":"[!-~]+" - }, - "CloudWatchEventsExecutionDataDetails":{ - "type":"structure", - "members":{ - "included":{ - "shape":"includedDetails", - "documentation":"

Indicates whether input or output was included in the response. Always true for API calls.

" - } - }, - "documentation":"

Provides details about execution input or output.

" - }, - "CloudWatchLogsLogGroup":{ - "type":"structure", - "members":{ - "logGroupArn":{ - "shape":"Arn", - "documentation":"

The ARN of the the CloudWatch log group to which you want your logs emitted to. The ARN must end with :*

" - } - }, - "documentation":"

" - }, - "ConflictException":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

Updating or deleting a resource can cause an inconsistent state. This error occurs when there're concurrent requests for DeleteStateMachineVersion, PublishStateMachineVersion, or UpdateStateMachine with the publish parameter set to true.

HTTP Status Code: 409

", - "exception":true - }, - "ConnectorParameters":{ - "type":"string", - "max":262144, - "min":0, - "sensitive":true - }, - "CreateActivityInput":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"Name", - "documentation":"

The name of the activity to create. This name must be unique for your Amazon Web Services account and region for 90 days. For more information, see Limits Related to State Machine Executions in the Step Functions Developer Guide.

A name must not contain:

  • white space

  • brackets < > { } [ ]

  • wildcard characters ? *

  • special characters \" # % \\ ^ | ~ ` $ & , ; : /

  • control characters (U+0000-001F, U+007F-009F)

To enable logging with CloudWatch Logs, the name should only contain 0-9, A-Z, a-z, - and _.

" - }, - "tags":{ - "shape":"TagList", - "documentation":"

The list of tags to add to a resource.

An array of key-value pairs. For more information, see Using Cost Allocation Tags in the Amazon Web Services Billing and Cost Management User Guide, and Controlling Access Using IAM Tags.

Tags may only contain Unicode letters, digits, white space, or these symbols: _ . : / = + - @.

" - }, - "encryptionConfiguration":{ - "shape":"EncryptionConfiguration", - "documentation":"

Settings to configure server-side encryption.

" - } - } - }, - "CreateActivityOutput":{ - "type":"structure", - "required":[ - "activityArn", - "creationDate" - ], - "members":{ - "activityArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies the created activity.

" - }, - "creationDate":{ - "shape":"Timestamp", - "documentation":"

The date the activity is created.

" - } - } - }, - "CreateStateMachineAliasInput":{ - "type":"structure", - "required":[ - "name", - "routingConfiguration" - ], - "members":{ - "description":{ - "shape":"AliasDescription", - "documentation":"

A description for the state machine alias.

" - }, - "name":{ - "shape":"CharacterRestrictedName", - "documentation":"

The name of the state machine alias.

To avoid conflict with version ARNs, don't use an integer in the name of the alias.

" - }, - "routingConfiguration":{ - "shape":"RoutingConfigurationList", - "documentation":"

The routing configuration of a state machine alias. The routing configuration shifts execution traffic between two state machine versions. routingConfiguration contains an array of RoutingConfig objects that specify up to two state machine versions. Step Functions then randomly choses which version to run an execution with based on the weight assigned to each RoutingConfig.

" - } - } - }, - "CreateStateMachineAliasOutput":{ - "type":"structure", - "required":[ - "stateMachineAliasArn", - "creationDate" - ], - "members":{ - "stateMachineAliasArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies the created state machine alias.

" - }, - "creationDate":{ - "shape":"Timestamp", - "documentation":"

The date the state machine alias was created.

" - } - } - }, - "CreateStateMachineInput":{ - "type":"structure", - "required":[ - "name", - "definition", - "roleArn" - ], - "members":{ - "name":{ - "shape":"Name", - "documentation":"

The name of the state machine.

A name must not contain:

  • white space

  • brackets < > { } [ ]

  • wildcard characters ? *

  • special characters \" # % \\ ^ | ~ ` $ & , ; : /

  • control characters (U+0000-001F, U+007F-009F)

To enable logging with CloudWatch Logs, the name should only contain 0-9, A-Z, a-z, - and _.

" - }, - "definition":{ - "shape":"Definition", - "documentation":"

The Amazon States Language definition of the state machine. See Amazon States Language.

" - }, - "roleArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the IAM role to use for this state machine.

" - }, - "type":{ - "shape":"StateMachineType", - "documentation":"

Determines whether a Standard or Express state machine is created. The default is STANDARD. You cannot update the type of a state machine once it has been created.

" - }, - "loggingConfiguration":{ - "shape":"LoggingConfiguration", - "documentation":"

Defines what execution history events are logged and where they are logged.

By default, the level is set to OFF. For more information see Log Levels in the Step Functions User Guide.

" - }, - "tags":{ - "shape":"TagList", - "documentation":"

Tags to be added when creating a state machine.

An array of key-value pairs. For more information, see Using Cost Allocation Tags in the Amazon Web Services Billing and Cost Management User Guide, and Controlling Access Using IAM Tags.

Tags may only contain Unicode letters, digits, white space, or these symbols: _ . : / = + - @.

" - }, - "tracingConfiguration":{ - "shape":"TracingConfiguration", - "documentation":"

Selects whether X-Ray tracing is enabled.

" - }, - "publish":{ - "shape":"Publish", - "documentation":"

Set to true to publish the first version of the state machine during creation. The default is false.

" - }, - "versionDescription":{ - "shape":"VersionDescription", - "documentation":"

Sets description about the state machine version. You can only set the description if the publish parameter is set to true. Otherwise, if you set versionDescription, but publish to false, this API action throws ValidationException.

" - }, - "encryptionConfiguration":{ - "shape":"EncryptionConfiguration", - "documentation":"

Settings to configure server-side encryption.

" - } - } - }, - "CreateStateMachineOutput":{ - "type":"structure", - "required":[ - "stateMachineArn", - "creationDate" - ], - "members":{ - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies the created state machine.

" - }, - "creationDate":{ - "shape":"Timestamp", - "documentation":"

The date the state machine is created.

" - }, - "stateMachineVersionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies the created state machine version. If you do not set the publish parameter to true, this field returns null value.

" - } - } - }, - "Definition":{ - "type":"string", - "max":1048576, - "min":1, - "sensitive":true - }, - "DeleteActivityInput":{ - "type":"structure", - "required":["activityArn"], - "members":{ - "activityArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the activity to delete.

" - } - } - }, - "DeleteActivityOutput":{ - "type":"structure", - "members":{ - } - }, - "DeleteStateMachineAliasInput":{ - "type":"structure", - "required":["stateMachineAliasArn"], - "members":{ - "stateMachineAliasArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine alias to delete.

" - } - } - }, - "DeleteStateMachineAliasOutput":{ - "type":"structure", - "members":{ - } - }, - "DeleteStateMachineInput":{ - "type":"structure", - "required":["stateMachineArn"], - "members":{ - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine to delete.

" - } - } - }, - "DeleteStateMachineOutput":{ - "type":"structure", - "members":{ - } - }, - "DeleteStateMachineVersionInput":{ - "type":"structure", - "required":["stateMachineVersionArn"], - "members":{ - "stateMachineVersionArn":{ - "shape":"LongArn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine version to delete.

" - } - } - }, - "DeleteStateMachineVersionOutput":{ - "type":"structure", - "members":{ - } - }, - "DescribeActivityInput":{ - "type":"structure", - "required":["activityArn"], - "members":{ - "activityArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the activity to describe.

" - } - } - }, - "DescribeActivityOutput":{ - "type":"structure", - "required":[ - "activityArn", - "name", - "creationDate" - ], - "members":{ - "activityArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies the activity.

" - }, - "name":{ - "shape":"Name", - "documentation":"

The name of the activity.

A name must not contain:

  • white space

  • brackets < > { } [ ]

  • wildcard characters ? *

  • special characters \" # % \\ ^ | ~ ` $ & , ; : /

  • control characters (U+0000-001F, U+007F-009F)

To enable logging with CloudWatch Logs, the name should only contain 0-9, A-Z, a-z, - and _.

" - }, - "creationDate":{ - "shape":"Timestamp", - "documentation":"

The date the activity is created.

" - }, - "encryptionConfiguration":{ - "shape":"EncryptionConfiguration", - "documentation":"

Settings for configured server-side encryption.

" - } - } - }, - "DescribeExecutionInput":{ - "type":"structure", - "required":["executionArn"], - "members":{ - "executionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the execution to describe.

" - }, - "includedData":{ - "shape":"IncludedData", - "documentation":"

If your state machine definition is encrypted with a KMS key, callers must have kms:Decrypt permission to decrypt the definition. Alternatively, you can call DescribeStateMachine API with includedData = METADATA_ONLY to get a successful response without the encrypted definition.

" - } - } - }, - "DescribeExecutionOutput":{ - "type":"structure", - "required":[ - "executionArn", - "stateMachineArn", - "status", - "startDate" - ], - "members":{ - "executionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies the execution.

" - }, - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the executed stated machine.

" - }, - "name":{ - "shape":"Name", - "documentation":"

The name of the execution.

A name must not contain:

  • white space

  • brackets < > { } [ ]

  • wildcard characters ? *

  • special characters \" # % \\ ^ | ~ ` $ & , ; : /

  • control characters (U+0000-001F, U+007F-009F)

To enable logging with CloudWatch Logs, the name should only contain 0-9, A-Z, a-z, - and _.

" - }, - "status":{ - "shape":"ExecutionStatus", - "documentation":"

The current status of the execution.

" - }, - "startDate":{ - "shape":"Timestamp", - "documentation":"

The date the execution is started.

" - }, - "stopDate":{ - "shape":"Timestamp", - "documentation":"

If the execution ended, the date the execution stopped.

" - }, - "input":{ - "shape":"SensitiveData", - "documentation":"

The string that contains the JSON input data of the execution. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "inputDetails":{"shape":"CloudWatchEventsExecutionDataDetails"}, - "output":{ - "shape":"SensitiveData", - "documentation":"

The JSON output data of the execution. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

This field is set only if the execution succeeds. If the execution fails, this field is null.

" - }, - "outputDetails":{"shape":"CloudWatchEventsExecutionDataDetails"}, - "traceHeader":{ - "shape":"TraceHeader", - "documentation":"

The X-Ray trace header that was passed to the execution.

" - }, - "mapRunArn":{ - "shape":"LongArn", - "documentation":"

The Amazon Resource Name (ARN) that identifies a Map Run, which dispatched this execution.

" - }, - "error":{ - "shape":"SensitiveError", - "documentation":"

The error string if the state machine execution failed.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

The cause string if the state machine execution failed.

" - }, - "stateMachineVersionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine version associated with the execution. The version ARN is a combination of state machine ARN and the version number separated by a colon (:). For example, stateMachineARN:1.

If you start an execution from a StartExecution request without specifying a state machine version or alias ARN, Step Functions returns a null value.

" - }, - "stateMachineAliasArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine alias associated with the execution. The alias ARN is a combination of state machine ARN and the alias name separated by a colon (:). For example, stateMachineARN:PROD.

If you start an execution from a StartExecution request with a state machine version ARN, this field will be null.

" - }, - "redriveCount":{ - "shape":"RedriveCount", - "documentation":"

The number of times you've redriven an execution. If you have not yet redriven an execution, the redriveCount is 0. This count is only updated if you successfully redrive an execution.

" - }, - "redriveDate":{ - "shape":"Timestamp", - "documentation":"

The date the execution was last redriven. If you have not yet redriven an execution, the redriveDate is null.

The redriveDate is unavailable if you redrive a Map Run that starts child workflow executions of type EXPRESS.

" - }, - "redriveStatus":{ - "shape":"ExecutionRedriveStatus", - "documentation":"

Indicates whether or not an execution can be redriven at a given point in time.

  • For executions of type STANDARD, redriveStatus is NOT_REDRIVABLE if calling the RedriveExecution API action would return the ExecutionNotRedrivable error.

  • For a Distributed Map that includes child workflows of type STANDARD, redriveStatus indicates whether or not the Map Run can redrive child workflow executions.

  • For a Distributed Map that includes child workflows of type EXPRESS, redriveStatus indicates whether or not the Map Run can redrive child workflow executions.

    You can redrive failed or timed out EXPRESS workflows only if they're a part of a Map Run. When you redrive the Map Run, these workflows are restarted using the StartExecution API action.

" - }, - "redriveStatusReason":{ - "shape":"SensitiveData", - "documentation":"

When redriveStatus is NOT_REDRIVABLE, redriveStatusReason specifies the reason why an execution cannot be redriven.

  • For executions of type STANDARD, or for a Distributed Map that includes child workflows of type STANDARD, redriveStatusReason can include one of the following reasons:

    • State machine is in DELETING status.

    • Execution is RUNNING and cannot be redriven.

    • Execution is SUCCEEDED and cannot be redriven.

    • Execution was started before the launch of RedriveExecution.

    • Execution history event limit exceeded.

    • Execution has exceeded the max execution time.

    • Execution redrivable period exceeded.

  • For a Distributed Map that includes child workflows of type EXPRESS, redriveStatusReason is only returned if the child workflows are not redrivable. This happens when the child workflow executions have completed successfully.

" - } - } - }, - "DescribeMapRunInput":{ - "type":"structure", - "required":["mapRunArn"], - "members":{ - "mapRunArn":{ - "shape":"LongArn", - "documentation":"

The Amazon Resource Name (ARN) that identifies a Map Run.

" - } - } - }, - "DescribeMapRunOutput":{ - "type":"structure", - "required":[ - "mapRunArn", - "executionArn", - "status", - "startDate", - "maxConcurrency", - "toleratedFailurePercentage", - "toleratedFailureCount", - "itemCounts", - "executionCounts" - ], - "members":{ - "mapRunArn":{ - "shape":"LongArn", - "documentation":"

The Amazon Resource Name (ARN) that identifies a Map Run.

" - }, - "executionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies the execution in which the Map Run was started.

" - }, - "status":{ - "shape":"MapRunStatus", - "documentation":"

The current status of the Map Run.

" - }, - "startDate":{ - "shape":"Timestamp", - "documentation":"

The date when the Map Run was started.

" - }, - "stopDate":{ - "shape":"Timestamp", - "documentation":"

The date when the Map Run was stopped.

" - }, - "maxConcurrency":{ - "shape":"MaxConcurrency", - "documentation":"

The maximum number of child workflow executions configured to run in parallel for the Map Run at the same time.

" - }, - "toleratedFailurePercentage":{ - "shape":"ToleratedFailurePercentage", - "documentation":"

The maximum percentage of failed child workflow executions before the Map Run fails.

" - }, - "toleratedFailureCount":{ - "shape":"ToleratedFailureCount", - "documentation":"

The maximum number of failed child workflow executions before the Map Run fails.

" - }, - "itemCounts":{ - "shape":"MapRunItemCounts", - "documentation":"

A JSON object that contains information about the total number of items, and the item count for each processing status, such as pending and failed.

" - }, - "executionCounts":{ - "shape":"MapRunExecutionCounts", - "documentation":"

A JSON object that contains information about the total number of child workflow executions for the Map Run, and the count of child workflow executions for each status, such as failed and succeeded.

" - }, - "redriveCount":{ - "shape":"RedriveCount", - "documentation":"

The number of times you've redriven a Map Run. If you have not yet redriven a Map Run, the redriveCount is 0. This count is only updated if you successfully redrive a Map Run.

" - }, - "redriveDate":{ - "shape":"Timestamp", - "documentation":"

The date a Map Run was last redriven. If you have not yet redriven a Map Run, the redriveDate is null.

" - } - } - }, - "DescribeStateMachineAliasInput":{ - "type":"structure", - "required":["stateMachineAliasArn"], - "members":{ - "stateMachineAliasArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine alias.

" - } - } - }, - "DescribeStateMachineAliasOutput":{ - "type":"structure", - "members":{ - "stateMachineAliasArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine alias.

" - }, - "name":{ - "shape":"Name", - "documentation":"

The name of the state machine alias.

" - }, - "description":{ - "shape":"AliasDescription", - "documentation":"

A description of the alias.

" - }, - "routingConfiguration":{ - "shape":"RoutingConfigurationList", - "documentation":"

The routing configuration of the alias.

" - }, - "creationDate":{ - "shape":"Timestamp", - "documentation":"

The date the state machine alias was created.

" - }, - "updateDate":{ - "shape":"Timestamp", - "documentation":"

The date the state machine alias was last updated.

For a newly created state machine, this is the same as the creation date.

" - } - } - }, - "DescribeStateMachineForExecutionInput":{ - "type":"structure", - "required":["executionArn"], - "members":{ - "executionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the execution you want state machine information for.

" - }, - "includedData":{ - "shape":"IncludedData", - "documentation":"

If your state machine definition is encrypted with a KMS key, callers must have kms:Decrypt permission to decrypt the definition. Alternatively, you can call the API with includedData = METADATA_ONLY to get a successful response without the encrypted definition.

" - } - } - }, - "DescribeStateMachineForExecutionOutput":{ - "type":"structure", - "required":[ - "stateMachineArn", - "name", - "definition", - "roleArn", - "updateDate" - ], - "members":{ - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine associated with the execution.

" - }, - "name":{ - "shape":"Name", - "documentation":"

The name of the state machine associated with the execution.

" - }, - "definition":{ - "shape":"Definition", - "documentation":"

The Amazon States Language definition of the state machine. See Amazon States Language.

" - }, - "roleArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the IAM role of the State Machine for the execution.

" - }, - "updateDate":{ - "shape":"Timestamp", - "documentation":"

The date and time the state machine associated with an execution was updated. For a newly created state machine, this is the creation date.

" - }, - "loggingConfiguration":{"shape":"LoggingConfiguration"}, - "tracingConfiguration":{ - "shape":"TracingConfiguration", - "documentation":"

Selects whether X-Ray tracing is enabled.

" - }, - "mapRunArn":{ - "shape":"LongArn", - "documentation":"

The Amazon Resource Name (ARN) of the Map Run that started the child workflow execution. This field is returned only if the executionArn is a child workflow execution that was started by a Distributed Map state.

" - }, - "label":{ - "shape":"MapRunLabel", - "documentation":"

A user-defined or an auto-generated string that identifies a Map state. This field is returned only if the executionArn is a child workflow execution that was started by a Distributed Map state.

" - }, - "revisionId":{ - "shape":"RevisionId", - "documentation":"

The revision identifier for the state machine. The first revision ID when you create the state machine is null.

Use the state machine revisionId parameter to compare the revision of a state machine with the configuration of the state machine used for executions without performing a diff of the properties, such as definition and roleArn.

" - }, - "encryptionConfiguration":{ - "shape":"EncryptionConfiguration", - "documentation":"

Settings to configure server-side encryption.

" - }, - "variableReferences":{ - "shape":"VariableReferences", - "documentation":"

A map of state name to a list of variables referenced by that state. States that do not use variable references will not be shown in the response.

" - } - } - }, - "DescribeStateMachineInput":{ - "type":"structure", - "required":["stateMachineArn"], - "members":{ - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine for which you want the information.

If you specify a state machine version ARN, this API returns details about that version. The version ARN is a combination of state machine ARN and the version number separated by a colon (:). For example, stateMachineARN:1.

" - }, - "includedData":{ - "shape":"IncludedData", - "documentation":"

If your state machine definition is encrypted with a KMS key, callers must have kms:Decrypt permission to decrypt the definition. Alternatively, you can call the API with includedData = METADATA_ONLY to get a successful response without the encrypted definition.

When calling a labelled ARN for an encrypted state machine, the includedData = METADATA_ONLY parameter will not apply because Step Functions needs to decrypt the entire state machine definition to get the Distributed Map state’s definition. In this case, the API caller needs to have kms:Decrypt permission.

" - } - } - }, - "DescribeStateMachineOutput":{ - "type":"structure", - "required":[ - "stateMachineArn", - "name", - "definition", - "roleArn", - "type", - "creationDate" - ], - "members":{ - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies the state machine.

If you specified a state machine version ARN in your request, the API returns the version ARN. The version ARN is a combination of state machine ARN and the version number separated by a colon (:). For example, stateMachineARN:1.

" - }, - "name":{ - "shape":"Name", - "documentation":"

The name of the state machine.

A name must not contain:

  • white space

  • brackets < > { } [ ]

  • wildcard characters ? *

  • special characters \" # % \\ ^ | ~ ` $ & , ; : /

  • control characters (U+0000-001F, U+007F-009F)

To enable logging with CloudWatch Logs, the name should only contain 0-9, A-Z, a-z, - and _.

" - }, - "status":{ - "shape":"StateMachineStatus", - "documentation":"

The current status of the state machine.

" - }, - "definition":{ - "shape":"Definition", - "documentation":"

The Amazon States Language definition of the state machine. See Amazon States Language.

If called with includedData = METADATA_ONLY, the returned definition will be {}.

" - }, - "roleArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the IAM role used when creating this state machine. (The IAM role maintains security by granting Step Functions access to Amazon Web Services resources.)

" - }, - "type":{ - "shape":"StateMachineType", - "documentation":"

The type of the state machine (STANDARD or EXPRESS).

" - }, - "creationDate":{ - "shape":"Timestamp", - "documentation":"

The date the state machine is created.

For a state machine version, creationDate is the date the version was created.

" - }, - "loggingConfiguration":{"shape":"LoggingConfiguration"}, - "tracingConfiguration":{ - "shape":"TracingConfiguration", - "documentation":"

Selects whether X-Ray tracing is enabled.

" - }, - "label":{ - "shape":"MapRunLabel", - "documentation":"

A user-defined or an auto-generated string that identifies a Map state. This parameter is present only if the stateMachineArn specified in input is a qualified state machine ARN.

" - }, - "revisionId":{ - "shape":"RevisionId", - "documentation":"

The revision identifier for the state machine.

Use the revisionId parameter to compare between versions of a state machine configuration used for executions without performing a diff of the properties, such as definition and roleArn.

" - }, - "description":{ - "shape":"VersionDescription", - "documentation":"

The description of the state machine version.

" - }, - "encryptionConfiguration":{ - "shape":"EncryptionConfiguration", - "documentation":"

Settings to configure server-side encryption.

" - }, - "variableReferences":{ - "shape":"VariableReferences", - "documentation":"

A map of state name to a list of variables referenced by that state. States that do not use variable references will not be shown in the response.

" - } - } - }, - "Enabled":{"type":"boolean"}, - "EncryptionConfiguration":{ - "type":"structure", - "required":["type"], - "members":{ - "kmsKeyId":{ - "shape":"KmsKeyId", - "documentation":"

An alias, alias ARN, key ID, or key ARN of a symmetric encryption KMS key to encrypt data. To specify a KMS key in a different Amazon Web Services account, you must use the key ARN or alias ARN.

" - }, - "kmsDataKeyReusePeriodSeconds":{ - "shape":"KmsDataKeyReusePeriodSeconds", - "documentation":"

Maximum duration that Step Functions will reuse data keys. When the period expires, Step Functions will call GenerateDataKey. Only applies to customer managed keys.

", - "box":true - }, - "type":{ - "shape":"EncryptionType", - "documentation":"

Encryption type

" - } - }, - "documentation":"

Settings to configure server-side encryption.

For additional control over security, you can encrypt your data using a customer-managed key for Step Functions state machines and activities. You can configure a symmetric KMS key and data key reuse period when creating or updating a State Machine, and when creating an Activity. The execution history and state machine definition will be encrypted with the key applied to the State Machine. Activity inputs will be encrypted with the key applied to the Activity.

Step Functions automatically enables encryption at rest using Amazon Web Services owned keys at no charge. However, KMS charges apply when using a customer managed key. For more information about pricing, see Key Management Service pricing.

For more information on KMS, see What is Key Management Service?

" - }, - "EncryptionType":{ - "type":"string", - "enum":[ - "AWS_OWNED_KEY", - "CUSTOMER_MANAGED_KMS_KEY" - ] - }, - "ErrorMessage":{"type":"string"}, - "EvaluationFailedEventDetails":{ - "type":"structure", - "required":["state"], - "members":{ - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - }, - "location":{ - "shape":"EvaluationFailureLocation", - "documentation":"

The location of the field in the state in which the evaluation error occurred.

" - }, - "state":{ - "shape":"StateName", - "documentation":"

The name of the state in which the evaluation error occurred.

" - } - }, - "documentation":"

Contains details about an evaluation failure that occurred while processing a state, for example, when a JSONata expression throws an error. This event will only be present in state machines that have QueryLanguage set to JSONata, or individual states set to JSONata.

" - }, - "EvaluationFailureLocation":{ - "type":"string", - "max":256, - "min":0, - "sensitive":true - }, - "EventId":{"type":"long"}, - "ExecutionAbortedEventDetails":{ - "type":"structure", - "members":{ - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - } - }, - "documentation":"

Contains details about an abort of an execution.

" - }, - "ExecutionAlreadyExists":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The execution has the same name as another execution (but a different input).

Executions with the same name and input are considered idempotent.

", - "exception":true - }, - "ExecutionDoesNotExist":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The specified execution does not exist.

", - "exception":true - }, - "ExecutionFailedEventDetails":{ - "type":"structure", - "members":{ - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - } - }, - "documentation":"

Contains details about an execution failure event.

" - }, - "ExecutionLimitExceeded":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The maximum number of running executions has been reached. Running executions must end or be stopped before a new execution can be started.

", - "exception":true - }, - "ExecutionList":{ - "type":"list", - "member":{"shape":"ExecutionListItem"} - }, - "ExecutionListItem":{ - "type":"structure", - "required":[ - "executionArn", - "stateMachineArn", - "name", - "status", - "startDate" - ], - "members":{ - "executionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies the execution.

" - }, - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine that ran the execution.

" - }, - "name":{ - "shape":"Name", - "documentation":"

The name of the execution.

A name must not contain:

  • white space

  • brackets < > { } [ ]

  • wildcard characters ? *

  • special characters \" # % \\ ^ | ~ ` $ & , ; : /

  • control characters (U+0000-001F, U+007F-009F)

To enable logging with CloudWatch Logs, the name should only contain 0-9, A-Z, a-z, - and _.

" - }, - "status":{ - "shape":"ExecutionStatus", - "documentation":"

The current status of the execution.

" - }, - "startDate":{ - "shape":"Timestamp", - "documentation":"

The date the execution started.

" - }, - "stopDate":{ - "shape":"Timestamp", - "documentation":"

If the execution already ended, the date the execution stopped.

" - }, - "mapRunArn":{ - "shape":"LongArn", - "documentation":"

The Amazon Resource Name (ARN) of a Map Run. This field is returned only if mapRunArn was specified in the ListExecutions API action. If stateMachineArn was specified in ListExecutions, the mapRunArn isn't returned.

" - }, - "itemCount":{ - "shape":"UnsignedInteger", - "documentation":"

The total number of items processed in a child workflow execution. This field is returned only if mapRunArn was specified in the ListExecutions API action. If stateMachineArn was specified in ListExecutions, the itemCount field isn't returned.

", - "box":true - }, - "stateMachineVersionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine version associated with the execution.

If the state machine execution was started with an unqualified ARN, it returns null.

If the execution was started using a stateMachineAliasArn, both the stateMachineAliasArn and stateMachineVersionArn parameters contain the respective values.

" - }, - "stateMachineAliasArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine alias used to start an execution.

If the state machine execution was started with an unqualified ARN or a version ARN, it returns null.

" - }, - "redriveCount":{ - "shape":"RedriveCount", - "documentation":"

The number of times you've redriven an execution. If you have not yet redriven an execution, the redriveCount is 0. This count is only updated when you successfully redrive an execution.

", - "box":true - }, - "redriveDate":{ - "shape":"Timestamp", - "documentation":"

The date the execution was last redriven.

" - } - }, - "documentation":"

Contains details about an execution.

" - }, - "ExecutionNotRedrivable":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The execution Amazon Resource Name (ARN) that you specified for executionArn cannot be redriven.

", - "exception":true - }, - "ExecutionRedriveFilter":{ - "type":"string", - "enum":[ - "REDRIVEN", - "NOT_REDRIVEN" - ] - }, - "ExecutionRedriveStatus":{ - "type":"string", - "enum":[ - "REDRIVABLE", - "NOT_REDRIVABLE", - "REDRIVABLE_BY_MAP_RUN" - ] - }, - "ExecutionRedrivenEventDetails":{ - "type":"structure", - "members":{ - "redriveCount":{ - "shape":"RedriveCount", - "documentation":"

The number of times you've redriven an execution. If you have not yet redriven an execution, the redriveCount is 0. This count is not updated for redrives that failed to start or are pending to be redriven.

" - } - }, - "documentation":"

Contains details about a redriven execution.

" - }, - "ExecutionStartedEventDetails":{ - "type":"structure", - "members":{ - "input":{ - "shape":"SensitiveData", - "documentation":"

The JSON data input to the execution. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "inputDetails":{ - "shape":"HistoryEventExecutionDataDetails", - "documentation":"

Contains details about the input for an execution history event.

" - }, - "roleArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the IAM role used for executing Lambda tasks.

" - }, - "stateMachineAliasArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies a state machine alias used for starting the state machine execution.

" - }, - "stateMachineVersionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies a state machine version used for starting the state machine execution.

" - } - }, - "documentation":"

Contains details about the start of the execution.

" - }, - "ExecutionStatus":{ - "type":"string", - "enum":[ - "RUNNING", - "SUCCEEDED", - "FAILED", - "TIMED_OUT", - "ABORTED", - "PENDING_REDRIVE" - ] - }, - "ExecutionSucceededEventDetails":{ - "type":"structure", - "members":{ - "output":{ - "shape":"SensitiveData", - "documentation":"

The JSON data output by the execution. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "outputDetails":{ - "shape":"HistoryEventExecutionDataDetails", - "documentation":"

Contains details about the output of an execution history event.

" - } - }, - "documentation":"

Contains details about the successful termination of the execution.

" - }, - "ExecutionTimedOutEventDetails":{ - "type":"structure", - "members":{ - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the timeout.

" - } - }, - "documentation":"

Contains details about the execution timeout that occurred during the execution.

" - }, - "GetActivityTaskInput":{ - "type":"structure", - "required":["activityArn"], - "members":{ - "activityArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the activity to retrieve tasks from (assigned when you create the task using CreateActivity.)

" - }, - "workerName":{ - "shape":"Name", - "documentation":"

You can provide an arbitrary name in order to identify the worker that the task is assigned to. This name is used when it is logged in the execution history.

" - } - } - }, - "GetActivityTaskOutput":{ - "type":"structure", - "members":{ - "taskToken":{ - "shape":"TaskToken", - "documentation":"

A token that identifies the scheduled task. This token must be copied and included in subsequent calls to SendTaskHeartbeat, SendTaskSuccess or SendTaskFailure in order to report the progress or completion of the task.

" - }, - "input":{ - "shape":"SensitiveDataJobInput", - "documentation":"

The string that contains the JSON input data for the task. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - } - } - }, - "GetExecutionHistoryInput":{ - "type":"structure", - "required":["executionArn"], - "members":{ - "executionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the execution.

" - }, - "maxResults":{ - "shape":"PageSize", - "documentation":"

The maximum number of results that are returned per call. You can use nextToken to obtain further pages of results. The default is 100 and the maximum allowed page size is 1000. A value of 0 uses the default.

This is only an upper limit. The actual number of results returned per call might be fewer than the specified maximum.

" - }, - "reverseOrder":{ - "shape":"ReverseOrder", - "documentation":"

Lists events in descending order of their timeStamp.

" - }, - "nextToken":{ - "shape":"PageToken", - "documentation":"

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

" - }, - "includeExecutionData":{ - "shape":"IncludeExecutionDataGetExecutionHistory", - "documentation":"

You can select whether execution data (input or output of a history event) is returned. The default is true.

" - } - } - }, - "GetExecutionHistoryOutput":{ - "type":"structure", - "required":["events"], - "members":{ - "events":{ - "shape":"HistoryEventList", - "documentation":"

The list of events that occurred in the execution.

" - }, - "nextToken":{ - "shape":"PageToken", - "documentation":"

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

" - } - } - }, - "HTTPBody":{"type":"string"}, - "HTTPHeaders":{"type":"string"}, - "HTTPMethod":{"type":"string"}, - "HTTPProtocol":{"type":"string"}, - "HTTPStatusCode":{"type":"string"}, - "HTTPStatusMessage":{"type":"string"}, - "HistoryEvent":{ - "type":"structure", - "required":[ - "timestamp", - "type", - "id" - ], - "members":{ - "timestamp":{ - "shape":"Timestamp", - "documentation":"

The date and time the event occurred.

" - }, - "type":{ - "shape":"HistoryEventType", - "documentation":"

The type of the event.

" - }, - "id":{ - "shape":"EventId", - "documentation":"

The id of the event. Events are numbered sequentially, starting at one.

" - }, - "previousEventId":{ - "shape":"EventId", - "documentation":"

The id of the previous event.

" - }, - "activityFailedEventDetails":{"shape":"ActivityFailedEventDetails"}, - "activityScheduleFailedEventDetails":{ - "shape":"ActivityScheduleFailedEventDetails", - "documentation":"

Contains details about an activity schedule event that failed during an execution.

" - }, - "activityScheduledEventDetails":{"shape":"ActivityScheduledEventDetails"}, - "activityStartedEventDetails":{"shape":"ActivityStartedEventDetails"}, - "activitySucceededEventDetails":{"shape":"ActivitySucceededEventDetails"}, - "activityTimedOutEventDetails":{"shape":"ActivityTimedOutEventDetails"}, - "taskFailedEventDetails":{ - "shape":"TaskFailedEventDetails", - "documentation":"

Contains details about the failure of a task.

" - }, - "taskScheduledEventDetails":{ - "shape":"TaskScheduledEventDetails", - "documentation":"

Contains details about a task that was scheduled.

" - }, - "taskStartFailedEventDetails":{ - "shape":"TaskStartFailedEventDetails", - "documentation":"

Contains details about a task that failed to start.

" - }, - "taskStartedEventDetails":{ - "shape":"TaskStartedEventDetails", - "documentation":"

Contains details about a task that was started.

" - }, - "taskSubmitFailedEventDetails":{ - "shape":"TaskSubmitFailedEventDetails", - "documentation":"

Contains details about a task that where the submit failed.

" - }, - "taskSubmittedEventDetails":{ - "shape":"TaskSubmittedEventDetails", - "documentation":"

Contains details about a submitted task.

" - }, - "taskSucceededEventDetails":{ - "shape":"TaskSucceededEventDetails", - "documentation":"

Contains details about a task that succeeded.

" - }, - "taskTimedOutEventDetails":{ - "shape":"TaskTimedOutEventDetails", - "documentation":"

Contains details about a task that timed out.

" - }, - "executionFailedEventDetails":{"shape":"ExecutionFailedEventDetails"}, - "executionStartedEventDetails":{"shape":"ExecutionStartedEventDetails"}, - "executionSucceededEventDetails":{"shape":"ExecutionSucceededEventDetails"}, - "executionAbortedEventDetails":{"shape":"ExecutionAbortedEventDetails"}, - "executionTimedOutEventDetails":{"shape":"ExecutionTimedOutEventDetails"}, - "executionRedrivenEventDetails":{ - "shape":"ExecutionRedrivenEventDetails", - "documentation":"

Contains details about the redrive attempt of an execution.

" - }, - "mapStateStartedEventDetails":{ - "shape":"MapStateStartedEventDetails", - "documentation":"

Contains details about Map state that was started.

" - }, - "mapIterationStartedEventDetails":{ - "shape":"MapIterationEventDetails", - "documentation":"

Contains details about an iteration of a Map state that was started.

" - }, - "mapIterationSucceededEventDetails":{ - "shape":"MapIterationEventDetails", - "documentation":"

Contains details about an iteration of a Map state that succeeded.

" - }, - "mapIterationFailedEventDetails":{ - "shape":"MapIterationEventDetails", - "documentation":"

Contains details about an iteration of a Map state that failed.

" - }, - "mapIterationAbortedEventDetails":{ - "shape":"MapIterationEventDetails", - "documentation":"

Contains details about an iteration of a Map state that was aborted.

" - }, - "lambdaFunctionFailedEventDetails":{"shape":"LambdaFunctionFailedEventDetails"}, - "lambdaFunctionScheduleFailedEventDetails":{"shape":"LambdaFunctionScheduleFailedEventDetails"}, - "lambdaFunctionScheduledEventDetails":{"shape":"LambdaFunctionScheduledEventDetails"}, - "lambdaFunctionStartFailedEventDetails":{ - "shape":"LambdaFunctionStartFailedEventDetails", - "documentation":"

Contains details about a lambda function that failed to start during an execution.

" - }, - "lambdaFunctionSucceededEventDetails":{ - "shape":"LambdaFunctionSucceededEventDetails", - "documentation":"

Contains details about a Lambda function that terminated successfully during an execution.

" - }, - "lambdaFunctionTimedOutEventDetails":{"shape":"LambdaFunctionTimedOutEventDetails"}, - "stateEnteredEventDetails":{"shape":"StateEnteredEventDetails"}, - "stateExitedEventDetails":{"shape":"StateExitedEventDetails"}, - "mapRunStartedEventDetails":{ - "shape":"MapRunStartedEventDetails", - "documentation":"

Contains details, such as mapRunArn, and the start date and time of a Map Run. mapRunArn is the Amazon Resource Name (ARN) of the Map Run that was started.

" - }, - "mapRunFailedEventDetails":{ - "shape":"MapRunFailedEventDetails", - "documentation":"

Contains error and cause details about a Map Run that failed.

" - }, - "mapRunRedrivenEventDetails":{ - "shape":"MapRunRedrivenEventDetails", - "documentation":"

Contains details about the redrive attempt of a Map Run.

" - }, - "evaluationFailedEventDetails":{ - "shape":"EvaluationFailedEventDetails", - "documentation":"

Contains details about an evaluation failure that occurred while processing a state.

" - } - }, - "documentation":"

Contains details about the events of an execution.

" - }, - "HistoryEventExecutionDataDetails":{ - "type":"structure", - "members":{ - "truncated":{ - "shape":"truncated", - "documentation":"

Indicates whether input or output was truncated in the response. Always false for API calls. In CloudWatch logs, the value will be true if the data is truncated due to size limits.

" - } - }, - "documentation":"

Provides details about input or output in an execution history event.

" - }, - "HistoryEventList":{ - "type":"list", - "member":{"shape":"HistoryEvent"}, - "documentation":"

Contains details about the events that occurred during an execution.

" - }, - "HistoryEventType":{ - "type":"string", - "enum":[ - "ActivityFailed", - "ActivityScheduled", - "ActivityScheduleFailed", - "ActivityStarted", - "ActivitySucceeded", - "ActivityTimedOut", - "ChoiceStateEntered", - "ChoiceStateExited", - "ExecutionAborted", - "ExecutionFailed", - "ExecutionStarted", - "ExecutionSucceeded", - "ExecutionTimedOut", - "FailStateEntered", - "LambdaFunctionFailed", - "LambdaFunctionScheduled", - "LambdaFunctionScheduleFailed", - "LambdaFunctionStarted", - "LambdaFunctionStartFailed", - "LambdaFunctionSucceeded", - "LambdaFunctionTimedOut", - "MapIterationAborted", - "MapIterationFailed", - "MapIterationStarted", - "MapIterationSucceeded", - "MapStateAborted", - "MapStateEntered", - "MapStateExited", - "MapStateFailed", - "MapStateStarted", - "MapStateSucceeded", - "ParallelStateAborted", - "ParallelStateEntered", - "ParallelStateExited", - "ParallelStateFailed", - "ParallelStateStarted", - "ParallelStateSucceeded", - "PassStateEntered", - "PassStateExited", - "SucceedStateEntered", - "SucceedStateExited", - "TaskFailed", - "TaskScheduled", - "TaskStarted", - "TaskStartFailed", - "TaskStateAborted", - "TaskStateEntered", - "TaskStateExited", - "TaskSubmitFailed", - "TaskSubmitted", - "TaskSucceeded", - "TaskTimedOut", - "WaitStateAborted", - "WaitStateEntered", - "WaitStateExited", - "MapRunAborted", - "MapRunFailed", - "MapRunStarted", - "MapRunSucceeded", - "ExecutionRedriven", - "MapRunRedriven", - "EvaluationFailed" - ] - }, - "Identity":{ - "type":"string", - "max":256 - }, - "IncludeExecutionData":{"type":"boolean"}, - "IncludeExecutionDataGetExecutionHistory":{ - "type":"boolean", - "box":true - }, - "IncludedData":{ - "type":"string", - "enum":[ - "ALL_DATA", - "METADATA_ONLY" - ] - }, - "InspectionData":{ - "type":"structure", - "members":{ - "input":{ - "shape":"SensitiveData", - "documentation":"

The raw state input.

" - }, - "afterArguments":{ - "shape":"SensitiveData", - "documentation":"

The input after Step Functions applies an Arguments filter. This event will only be present when QueryLanguage for the state machine or individual states is set to JSONata. For more info, see Transforming data with Step Functions.

" - }, - "afterInputPath":{ - "shape":"SensitiveData", - "documentation":"

The input after Step Functions applies the InputPath filter. Not populated when QueryLanguage is JSONata.

" - }, - "afterParameters":{ - "shape":"SensitiveData", - "documentation":"

The effective input after Step Functions applies the Parameters filter. Not populated when QueryLanguage is JSONata.

" - }, - "result":{ - "shape":"SensitiveData", - "documentation":"

The state's raw result.

" - }, - "afterResultSelector":{ - "shape":"SensitiveData", - "documentation":"

The effective result after Step Functions applies the ResultSelector filter. Not populated when QueryLanguage is JSONata.

" - }, - "afterResultPath":{ - "shape":"SensitiveData", - "documentation":"

The effective result combined with the raw state input after Step Functions applies the ResultPath filter. Not populated when QueryLanguage is JSONata.

" - }, - "request":{ - "shape":"InspectionDataRequest", - "documentation":"

The raw HTTP request that is sent when you test an HTTP Task.

" - }, - "response":{ - "shape":"InspectionDataResponse", - "documentation":"

The raw HTTP response that is returned when you test an HTTP Task.

" - }, - "variables":{ - "shape":"SensitiveData", - "documentation":"

JSON string that contains the set of workflow variables after execution of the state. The set will include variables assigned in the state and variables set up as test state input.

" - } - }, - "documentation":"

Contains additional details about the state's execution, including its input and output data processing flow, and HTTP request and response information.

", - "sensitive":true - }, - "InspectionDataRequest":{ - "type":"structure", - "members":{ - "protocol":{ - "shape":"HTTPProtocol", - "documentation":"

The protocol used to make the HTTP request.

" - }, - "method":{ - "shape":"HTTPMethod", - "documentation":"

The HTTP method used for the HTTP request.

" - }, - "url":{ - "shape":"URL", - "documentation":"

The API endpoint used for the HTTP request.

" - }, - "headers":{ - "shape":"HTTPHeaders", - "documentation":"

The request headers associated with the HTTP request.

" - }, - "body":{ - "shape":"HTTPBody", - "documentation":"

The request body for the HTTP request.

" - } - }, - "documentation":"

Contains additional details about the state's execution, including its input and output data processing flow, and HTTP request information.

" - }, - "InspectionDataResponse":{ - "type":"structure", - "members":{ - "protocol":{ - "shape":"HTTPProtocol", - "documentation":"

The protocol used to return the HTTP response.

" - }, - "statusCode":{ - "shape":"HTTPStatusCode", - "documentation":"

The HTTP response status code for the HTTP response.

" - }, - "statusMessage":{ - "shape":"HTTPStatusMessage", - "documentation":"

The message associated with the HTTP status code.

" - }, - "headers":{ - "shape":"HTTPHeaders", - "documentation":"

The response headers associated with the HTTP response.

" - }, - "body":{ - "shape":"HTTPBody", - "documentation":"

The HTTP response returned.

" - } - }, - "documentation":"

Contains additional details about the state's execution, including its input and output data processing flow, and HTTP response information. The inspectionLevel request parameter specifies which details are returned.

" - }, - "InspectionLevel":{ - "type":"string", - "enum":[ - "INFO", - "DEBUG", - "TRACE" - ] - }, - "InvalidArn":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The provided Amazon Resource Name (ARN) is not valid.

", - "exception":true - }, - "InvalidDefinition":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The provided Amazon States Language definition is not valid.

", - "exception":true - }, - "InvalidEncryptionConfiguration":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

Received when encryptionConfiguration is specified but various conditions exist which make the configuration invalid. For example, if type is set to CUSTOMER_MANAGED_KMS_KEY, but kmsKeyId is null, or kmsDataKeyReusePeriodSeconds is not between 60 and 900, or the KMS key is not symmetric or inactive.

", - "exception":true - }, - "InvalidExecutionInput":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The provided JSON input data is not valid.

", - "exception":true - }, - "InvalidLoggingConfiguration":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

Configuration is not valid.

", - "exception":true - }, - "InvalidName":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The provided name is not valid.

", - "exception":true - }, - "InvalidOutput":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The provided JSON output data is not valid.

", - "exception":true - }, - "InvalidToken":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The provided token is not valid.

", - "exception":true - }, - "InvalidTracingConfiguration":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

Your tracingConfiguration key does not match, or enabled has not been set to true or false.

", - "exception":true - }, - "KmsAccessDeniedException":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

Either your KMS key policy or API caller does not have the required permissions.

", - "exception":true - }, - "KmsDataKeyReusePeriodSeconds":{ - "type":"integer", - "box":true, - "max":900, - "min":60 - }, - "KmsInvalidStateException":{ - "type":"structure", - "members":{ - "kmsKeyState":{ - "shape":"KmsKeyState", - "documentation":"

Current status of the KMS; key. For example: DISABLED, PENDING_DELETION, PENDING_IMPORT, UNAVAILABLE, CREATING.

" - }, - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The KMS key is not in valid state, for example: Disabled or Deleted.

", - "exception":true - }, - "KmsKeyId":{ - "type":"string", - "max":2048, - "min":1 - }, - "KmsKeyState":{ - "type":"string", - "enum":[ - "DISABLED", - "PENDING_DELETION", - "PENDING_IMPORT", - "UNAVAILABLE", - "CREATING" - ] - }, - "KmsThrottlingException":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

Received when KMS returns ThrottlingException for a KMS call that Step Functions makes on behalf of the caller.

", - "exception":true - }, - "LambdaFunctionFailedEventDetails":{ - "type":"structure", - "members":{ - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - } - }, - "documentation":"

Contains details about a Lambda function that failed during an execution.

" - }, - "LambdaFunctionScheduleFailedEventDetails":{ - "type":"structure", - "members":{ - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - } - }, - "documentation":"

Contains details about a failed Lambda function schedule event that occurred during an execution.

" - }, - "LambdaFunctionScheduledEventDetails":{ - "type":"structure", - "required":["resource"], - "members":{ - "resource":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the scheduled Lambda function.

" - }, - "input":{ - "shape":"SensitiveData", - "documentation":"

The JSON data input to the Lambda function. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "inputDetails":{ - "shape":"HistoryEventExecutionDataDetails", - "documentation":"

Contains details about input for an execution history event.

" - }, - "timeoutInSeconds":{ - "shape":"TimeoutInSeconds", - "documentation":"

The maximum allowed duration of the Lambda function.

", - "box":true - }, - "taskCredentials":{ - "shape":"TaskCredentials", - "documentation":"

The credentials that Step Functions uses for the task.

" - } - }, - "documentation":"

Contains details about a Lambda function scheduled during an execution.

" - }, - "LambdaFunctionStartFailedEventDetails":{ - "type":"structure", - "members":{ - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - } - }, - "documentation":"

Contains details about a lambda function that failed to start during an execution.

" - }, - "LambdaFunctionSucceededEventDetails":{ - "type":"structure", - "members":{ - "output":{ - "shape":"SensitiveData", - "documentation":"

The JSON data output by the Lambda function. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "outputDetails":{ - "shape":"HistoryEventExecutionDataDetails", - "documentation":"

Contains details about the output of an execution history event.

" - } - }, - "documentation":"

Contains details about a Lambda function that successfully terminated during an execution.

" - }, - "LambdaFunctionTimedOutEventDetails":{ - "type":"structure", - "members":{ - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the timeout.

" - } - }, - "documentation":"

Contains details about a Lambda function timeout that occurred during an execution.

" - }, - "ListActivitiesInput":{ - "type":"structure", - "members":{ - "maxResults":{ - "shape":"PageSize", - "documentation":"

The maximum number of results that are returned per call. You can use nextToken to obtain further pages of results. The default is 100 and the maximum allowed page size is 1000. A value of 0 uses the default.

This is only an upper limit. The actual number of results returned per call might be fewer than the specified maximum.

" - }, - "nextToken":{ - "shape":"PageToken", - "documentation":"

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

" - } - } - }, - "ListActivitiesOutput":{ - "type":"structure", - "required":["activities"], - "members":{ - "activities":{ - "shape":"ActivityList", - "documentation":"

The list of activities.

" - }, - "nextToken":{ - "shape":"PageToken", - "documentation":"

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

" - } - } - }, - "ListExecutionsInput":{ - "type":"structure", - "members":{ - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine whose executions is listed.

You can specify either a mapRunArn or a stateMachineArn, but not both.

You can also return a list of executions associated with a specific alias or version, by specifying an alias ARN or a version ARN in the stateMachineArn parameter.

" - }, - "statusFilter":{ - "shape":"ExecutionStatus", - "documentation":"

If specified, only list the executions whose current execution status matches the given filter.

" - }, - "maxResults":{ - "shape":"PageSize", - "documentation":"

The maximum number of results that are returned per call. You can use nextToken to obtain further pages of results. The default is 100 and the maximum allowed page size is 1000. A value of 0 uses the default.

This is only an upper limit. The actual number of results returned per call might be fewer than the specified maximum.

" - }, - "nextToken":{ - "shape":"ListExecutionsPageToken", - "documentation":"

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

" - }, - "mapRunArn":{ - "shape":"LongArn", - "documentation":"

The Amazon Resource Name (ARN) of the Map Run that started the child workflow executions. If the mapRunArn field is specified, a list of all of the child workflow executions started by a Map Run is returned. For more information, see Examining Map Run in the Step Functions Developer Guide.

You can specify either a mapRunArn or a stateMachineArn, but not both.

" - }, - "redriveFilter":{ - "shape":"ExecutionRedriveFilter", - "documentation":"

Sets a filter to list executions based on whether or not they have been redriven.

For a Distributed Map, redriveFilter sets a filter to list child workflow executions based on whether or not they have been redriven.

If you do not provide a redriveFilter, Step Functions returns a list of both redriven and non-redriven executions.

If you provide a state machine ARN in redriveFilter, the API returns a validation exception.

" - } - } - }, - "ListExecutionsOutput":{ - "type":"structure", - "required":["executions"], - "members":{ - "executions":{ - "shape":"ExecutionList", - "documentation":"

The list of matching executions.

" - }, - "nextToken":{ - "shape":"ListExecutionsPageToken", - "documentation":"

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

" - } - } - }, - "ListExecutionsPageToken":{ - "type":"string", - "max":3096, - "min":1 - }, - "ListMapRunsInput":{ - "type":"structure", - "required":["executionArn"], - "members":{ - "executionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the execution for which the Map Runs must be listed.

" - }, - "maxResults":{ - "shape":"PageSize", - "documentation":"

The maximum number of results that are returned per call. You can use nextToken to obtain further pages of results. The default is 100 and the maximum allowed page size is 1000. A value of 0 uses the default.

This is only an upper limit. The actual number of results returned per call might be fewer than the specified maximum.

" - }, - "nextToken":{ - "shape":"PageToken", - "documentation":"

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

" - } - } - }, - "ListMapRunsOutput":{ - "type":"structure", - "required":["mapRuns"], - "members":{ - "mapRuns":{ - "shape":"MapRunList", - "documentation":"

An array that lists information related to a Map Run, such as the Amazon Resource Name (ARN) of the Map Run and the ARN of the state machine that started the Map Run.

" - }, - "nextToken":{ - "shape":"PageToken", - "documentation":"

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

" - } - } - }, - "ListStateMachineAliasesInput":{ - "type":"structure", - "required":["stateMachineArn"], - "members":{ - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine for which you want to list aliases.

If you specify a state machine version ARN, this API returns a list of aliases for that version.

" - }, - "nextToken":{ - "shape":"PageToken", - "documentation":"

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

" - }, - "maxResults":{ - "shape":"PageSize", - "documentation":"

The maximum number of results that are returned per call. You can use nextToken to obtain further pages of results. The default is 100 and the maximum allowed page size is 1000. A value of 0 uses the default.

This is only an upper limit. The actual number of results returned per call might be fewer than the specified maximum.

" - } - } - }, - "ListStateMachineAliasesOutput":{ - "type":"structure", - "required":["stateMachineAliases"], - "members":{ - "stateMachineAliases":{ - "shape":"StateMachineAliasList", - "documentation":"

Aliases for the state machine.

" - }, - "nextToken":{ - "shape":"PageToken", - "documentation":"

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

" - } - } - }, - "ListStateMachineVersionsInput":{ - "type":"structure", - "required":["stateMachineArn"], - "members":{ - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine.

" - }, - "nextToken":{ - "shape":"PageToken", - "documentation":"

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

" - }, - "maxResults":{ - "shape":"PageSize", - "documentation":"

The maximum number of results that are returned per call. You can use nextToken to obtain further pages of results. The default is 100 and the maximum allowed page size is 1000. A value of 0 uses the default.

This is only an upper limit. The actual number of results returned per call might be fewer than the specified maximum.

" - } - } - }, - "ListStateMachineVersionsOutput":{ - "type":"structure", - "required":["stateMachineVersions"], - "members":{ - "stateMachineVersions":{ - "shape":"StateMachineVersionList", - "documentation":"

Versions for the state machine.

" - }, - "nextToken":{ - "shape":"PageToken", - "documentation":"

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

" - } - } - }, - "ListStateMachinesInput":{ - "type":"structure", - "members":{ - "maxResults":{ - "shape":"PageSize", - "documentation":"

The maximum number of results that are returned per call. You can use nextToken to obtain further pages of results. The default is 100 and the maximum allowed page size is 1000. A value of 0 uses the default.

This is only an upper limit. The actual number of results returned per call might be fewer than the specified maximum.

" - }, - "nextToken":{ - "shape":"PageToken", - "documentation":"

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

" - } - } - }, - "ListStateMachinesOutput":{ - "type":"structure", - "required":["stateMachines"], - "members":{ - "stateMachines":{"shape":"StateMachineList"}, - "nextToken":{ - "shape":"PageToken", - "documentation":"

If nextToken is returned, there are more results available. The value of nextToken is a unique pagination token for each page. Make the call again using the returned token to retrieve the next page. Keep all other arguments unchanged. Each pagination token expires after 24 hours. Using an expired pagination token will return an HTTP 400 InvalidToken error.

" - } - } - }, - "ListTagsForResourceInput":{ - "type":"structure", - "required":["resourceArn"], - "members":{ - "resourceArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) for the Step Functions state machine or activity.

" - } - } - }, - "ListTagsForResourceOutput":{ - "type":"structure", - "members":{ - "tags":{ - "shape":"TagList", - "documentation":"

An array of tags associated with the resource.

" - } - } - }, - "LogDestination":{ - "type":"structure", - "members":{ - "cloudWatchLogsLogGroup":{ - "shape":"CloudWatchLogsLogGroup", - "documentation":"

An object describing a CloudWatch log group. For more information, see AWS::Logs::LogGroup in the CloudFormation User Guide.

" - } - }, - "documentation":"

" - }, - "LogDestinationList":{ - "type":"list", - "member":{"shape":"LogDestination"} - }, - "LogLevel":{ - "type":"string", - "enum":[ - "ALL", - "ERROR", - "FATAL", - "OFF" - ] - }, - "LoggingConfiguration":{ - "type":"structure", - "members":{ - "level":{ - "shape":"LogLevel", - "documentation":"

Defines which category of execution history events are logged.

" - }, - "includeExecutionData":{ - "shape":"IncludeExecutionData", - "documentation":"

Determines whether execution data is included in your log. When set to false, data is excluded.

" - }, - "destinations":{ - "shape":"LogDestinationList", - "documentation":"

An array of objects that describes where your execution history events will be logged. Limited to size 1. Required, if your log level is not set to OFF.

" - } - }, - "documentation":"

The LoggingConfiguration data type is used to set CloudWatch Logs options.

" - }, - "LongArn":{ - "type":"string", - "max":2000, - "min":1 - }, - "LongObject":{"type":"long"}, - "MapIterationEventDetails":{ - "type":"structure", - "members":{ - "name":{ - "shape":"Name", - "documentation":"

The name of the iteration’s parent Map state.

" - }, - "index":{ - "shape":"UnsignedInteger", - "documentation":"

The index of the array belonging to the Map state iteration.

" - } - }, - "documentation":"

Contains details about an iteration of a Map state.

" - }, - "MapRunExecutionCounts":{ - "type":"structure", - "required":[ - "pending", - "running", - "succeeded", - "failed", - "timedOut", - "aborted", - "total", - "resultsWritten" - ], - "members":{ - "pending":{ - "shape":"UnsignedLong", - "documentation":"

The total number of child workflow executions that were started by a Map Run, but haven't started executing yet.

" - }, - "running":{ - "shape":"UnsignedLong", - "documentation":"

The total number of child workflow executions that were started by a Map Run and are currently in-progress.

" - }, - "succeeded":{ - "shape":"UnsignedLong", - "documentation":"

The total number of child workflow executions that were started by a Map Run and have completed successfully.

" - }, - "failed":{ - "shape":"UnsignedLong", - "documentation":"

The total number of child workflow executions that were started by a Map Run, but have failed.

" - }, - "timedOut":{ - "shape":"UnsignedLong", - "documentation":"

The total number of child workflow executions that were started by a Map Run and have timed out.

" - }, - "aborted":{ - "shape":"UnsignedLong", - "documentation":"

The total number of child workflow executions that were started by a Map Run and were running, but were either stopped by the user or by Step Functions because the Map Run failed.

" - }, - "total":{ - "shape":"UnsignedLong", - "documentation":"

The total number of child workflow executions that were started by a Map Run.

" - }, - "resultsWritten":{ - "shape":"UnsignedLong", - "documentation":"

Returns the count of child workflow executions whose results were written by ResultWriter. For more information, see ResultWriter in the Step Functions Developer Guide.

" - }, - "failuresNotRedrivable":{ - "shape":"LongObject", - "documentation":"

The number of FAILED, ABORTED, or TIMED_OUT child workflow executions that cannot be redriven because their execution status is terminal. For example, child workflows with an execution status of FAILED, ABORTED, or TIMED_OUT and a redriveStatus of NOT_REDRIVABLE.

" - }, - "pendingRedrive":{ - "shape":"LongObject", - "documentation":"

The number of unsuccessful child workflow executions currently waiting to be redriven. The status of these child workflow executions could be FAILED, ABORTED, or TIMED_OUT in the original execution attempt or a previous redrive attempt.

" - } - }, - "documentation":"

Contains details about all of the child workflow executions started by a Map Run.

" - }, - "MapRunFailedEventDetails":{ - "type":"structure", - "members":{ - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the Map Run failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - } - }, - "documentation":"

Contains details about a Map Run failure event that occurred during a state machine execution.

" - }, - "MapRunItemCounts":{ - "type":"structure", - "required":[ - "pending", - "running", - "succeeded", - "failed", - "timedOut", - "aborted", - "total", - "resultsWritten" - ], - "members":{ - "pending":{ - "shape":"UnsignedLong", - "documentation":"

The total number of items to process in child workflow executions that haven't started running yet.

" - }, - "running":{ - "shape":"UnsignedLong", - "documentation":"

The total number of items being processed in child workflow executions that are currently in-progress.

" - }, - "succeeded":{ - "shape":"UnsignedLong", - "documentation":"

The total number of items processed in child workflow executions that have completed successfully.

" - }, - "failed":{ - "shape":"UnsignedLong", - "documentation":"

The total number of items processed in child workflow executions that have failed.

" - }, - "timedOut":{ - "shape":"UnsignedLong", - "documentation":"

The total number of items processed in child workflow executions that have timed out.

" - }, - "aborted":{ - "shape":"UnsignedLong", - "documentation":"

The total number of items processed in child workflow executions that were either stopped by the user or by Step Functions, because the Map Run failed.

" - }, - "total":{ - "shape":"UnsignedLong", - "documentation":"

The total number of items processed in all the child workflow executions started by a Map Run.

" - }, - "resultsWritten":{ - "shape":"UnsignedLong", - "documentation":"

Returns the count of items whose results were written by ResultWriter. For more information, see ResultWriter in the Step Functions Developer Guide.

" - }, - "failuresNotRedrivable":{ - "shape":"LongObject", - "documentation":"

The number of FAILED, ABORTED, or TIMED_OUT items in child workflow executions that cannot be redriven because the execution status of those child workflows is terminal. For example, child workflows with an execution status of FAILED, ABORTED, or TIMED_OUT and a redriveStatus of NOT_REDRIVABLE.

" - }, - "pendingRedrive":{ - "shape":"LongObject", - "documentation":"

The number of unsuccessful items in child workflow executions currently waiting to be redriven.

" - } - }, - "documentation":"

Contains details about items that were processed in all of the child workflow executions that were started by a Map Run.

" - }, - "MapRunLabel":{"type":"string"}, - "MapRunList":{ - "type":"list", - "member":{"shape":"MapRunListItem"} - }, - "MapRunListItem":{ - "type":"structure", - "required":[ - "executionArn", - "mapRunArn", - "stateMachineArn", - "startDate" - ], - "members":{ - "executionArn":{ - "shape":"Arn", - "documentation":"

The executionArn of the execution from which the Map Run was started.

" - }, - "mapRunArn":{ - "shape":"LongArn", - "documentation":"

The Amazon Resource Name (ARN) of the Map Run.

" - }, - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the executed state machine.

" - }, - "startDate":{ - "shape":"Timestamp", - "documentation":"

The date on which the Map Run started.

" - }, - "stopDate":{ - "shape":"Timestamp", - "documentation":"

The date on which the Map Run stopped.

" - } - }, - "documentation":"

Contains details about a specific Map Run.

" - }, - "MapRunRedrivenEventDetails":{ - "type":"structure", - "members":{ - "mapRunArn":{ - "shape":"LongArn", - "documentation":"

The Amazon Resource Name (ARN) of a Map Run that was redriven.

" - }, - "redriveCount":{ - "shape":"RedriveCount", - "documentation":"

The number of times the Map Run has been redriven at this point in the execution's history including this event. The redrive count for a redriven Map Run is always greater than 0.

" - } - }, - "documentation":"

Contains details about a Map Run that was redriven.

" - }, - "MapRunStartedEventDetails":{ - "type":"structure", - "members":{ - "mapRunArn":{ - "shape":"LongArn", - "documentation":"

The Amazon Resource Name (ARN) of a Map Run that was started.

" - } - }, - "documentation":"

Contains details about a Map Run that was started during a state machine execution.

" - }, - "MapRunStatus":{ - "type":"string", - "enum":[ - "RUNNING", - "SUCCEEDED", - "FAILED", - "ABORTED" - ] - }, - "MapStateStartedEventDetails":{ - "type":"structure", - "members":{ - "length":{ - "shape":"UnsignedInteger", - "documentation":"

The size of the array for Map state iterations.

" - } - }, - "documentation":"

Details about a Map state that was started.

" - }, - "MaxConcurrency":{ - "type":"integer", - "min":0 - }, - "MissingRequiredParameter":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

Request is missing a required parameter. This error occurs if both definition and roleArn are not specified.

", - "exception":true - }, - "Name":{ - "type":"string", - "max":80, - "min":1 - }, - "PageSize":{ - "type":"integer", - "max":1000, - "min":0 - }, - "PageToken":{ - "type":"string", - "max":1024, - "min":1 - }, - "Publish":{"type":"boolean"}, - "PublishStateMachineVersionInput":{ - "type":"structure", - "required":["stateMachineArn"], - "members":{ - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine.

" - }, - "revisionId":{ - "shape":"RevisionId", - "documentation":"

Only publish the state machine version if the current state machine's revision ID matches the specified ID.

Use this option to avoid publishing a version if the state machine changed since you last updated it. If the specified revision ID doesn't match the state machine's current revision ID, the API returns ConflictException.

To specify an initial revision ID for a state machine with no revision ID assigned, specify the string INITIAL for the revisionId parameter. For example, you can specify a revisionID of INITIAL when you create a state machine using the CreateStateMachine API action.

" - }, - "description":{ - "shape":"VersionDescription", - "documentation":"

An optional description of the state machine version.

" - } - } - }, - "PublishStateMachineVersionOutput":{ - "type":"structure", - "required":[ - "creationDate", - "stateMachineVersionArn" - ], - "members":{ - "creationDate":{ - "shape":"Timestamp", - "documentation":"

The date the version was created.

" - }, - "stateMachineVersionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) (ARN) that identifies the state machine version.

" - } - } - }, - "RedriveCount":{ - "type":"integer", - "box":true - }, - "RedriveExecutionInput":{ - "type":"structure", - "required":["executionArn"], - "members":{ - "executionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the execution to be redriven.

" - }, - "clientToken":{ - "shape":"ClientToken", - "documentation":"

A unique, case-sensitive identifier that you provide to ensure the idempotency of the request. If you don’t specify a client token, the Amazon Web Services SDK automatically generates a client token and uses it for the request to ensure idempotency. The API will return idempotent responses for the last 10 client tokens used to successfully redrive the execution. These client tokens are valid for up to 15 minutes after they are first used.

", - "idempotencyToken":true - } - } - }, - "RedriveExecutionOutput":{ - "type":"structure", - "required":["redriveDate"], - "members":{ - "redriveDate":{ - "shape":"Timestamp", - "documentation":"

The date the execution was last redriven.

" - } - } - }, - "ResourceNotFound":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"}, - "resourceName":{"shape":"Arn"} - }, - "documentation":"

Could not find the referenced resource.

", - "exception":true - }, - "RevealSecrets":{"type":"boolean"}, - "ReverseOrder":{"type":"boolean"}, - "RevisionId":{"type":"string"}, - "RoutingConfigurationList":{ - "type":"list", - "member":{"shape":"RoutingConfigurationListItem"}, - "max":2, - "min":1 - }, - "RoutingConfigurationListItem":{ - "type":"structure", - "required":[ - "stateMachineVersionArn", - "weight" - ], - "members":{ - "stateMachineVersionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies one or two state machine versions defined in the routing configuration.

If you specify the ARN of a second version, it must belong to the same state machine as the first version.

" - }, - "weight":{ - "shape":"VersionWeight", - "documentation":"

The percentage of traffic you want to route to a state machine version. The sum of the weights in the routing configuration must be equal to 100.

" - } - }, - "documentation":"

Contains details about the routing configuration of a state machine alias. In a routing configuration, you define an array of objects that specify up to two state machine versions. You also specify the percentage of traffic to be routed to each version.

" - }, - "SendTaskFailureInput":{ - "type":"structure", - "required":["taskToken"], - "members":{ - "taskToken":{ - "shape":"TaskToken", - "documentation":"

The token that represents this task. Task tokens are generated by Step Functions when tasks are assigned to a worker, or in the context object when a workflow enters a task state. See GetActivityTaskOutput$taskToken.

" - }, - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - } - } - }, - "SendTaskFailureOutput":{ - "type":"structure", - "members":{ - } - }, - "SendTaskHeartbeatInput":{ - "type":"structure", - "required":["taskToken"], - "members":{ - "taskToken":{ - "shape":"TaskToken", - "documentation":"

The token that represents this task. Task tokens are generated by Step Functions when tasks are assigned to a worker, or in the context object when a workflow enters a task state. See GetActivityTaskOutput$taskToken.

" - } - } - }, - "SendTaskHeartbeatOutput":{ - "type":"structure", - "members":{ - } - }, - "SendTaskSuccessInput":{ - "type":"structure", - "required":[ - "taskToken", - "output" - ], - "members":{ - "taskToken":{ - "shape":"TaskToken", - "documentation":"

The token that represents this task. Task tokens are generated by Step Functions when tasks are assigned to a worker, or in the context object when a workflow enters a task state. See GetActivityTaskOutput$taskToken.

" - }, - "output":{ - "shape":"SensitiveData", - "documentation":"

The JSON output of the task. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - } - } - }, - "SendTaskSuccessOutput":{ - "type":"structure", - "members":{ - } - }, - "SensitiveCause":{ - "type":"string", - "max":32768, - "min":0, - "sensitive":true - }, - "SensitiveData":{ - "type":"string", - "max":262144, - "sensitive":true - }, - "SensitiveDataJobInput":{ - "type":"string", - "max":262144, - "sensitive":true - }, - "SensitiveError":{ - "type":"string", - "max":256, - "min":0, - "sensitive":true - }, - "ServiceQuotaExceededException":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The request would cause a service quota to be exceeded.

HTTP Status Code: 402

", - "exception":true - }, - "StartExecutionInput":{ - "type":"structure", - "required":["stateMachineArn"], - "members":{ - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine to execute.

The stateMachineArn parameter accepts one of the following inputs:

  • An unqualified state machine ARN – Refers to a state machine ARN that isn't qualified with a version or alias ARN. The following is an example of an unqualified state machine ARN.

    arn:<partition>:states:<region>:<account-id>:stateMachine:<myStateMachine>

    Step Functions doesn't associate state machine executions that you start with an unqualified ARN with a version. This is true even if that version uses the same revision that the execution used.

  • A state machine version ARN – Refers to a version ARN, which is a combination of state machine ARN and the version number separated by a colon (:). The following is an example of the ARN for version 10.

    arn:<partition>:states:<region>:<account-id>:stateMachine:<myStateMachine>:10

    Step Functions doesn't associate executions that you start with a version ARN with any aliases that point to that version.

  • A state machine alias ARN – Refers to an alias ARN, which is a combination of state machine ARN and the alias name separated by a colon (:). The following is an example of the ARN for an alias named PROD.

    arn:<partition>:states:<region>:<account-id>:stateMachine:<myStateMachine:PROD>

    Step Functions associates executions that you start with an alias ARN with that alias and the state machine version used for that execution.

" - }, - "name":{ - "shape":"Name", - "documentation":"

Optional name of the execution. This name must be unique for your Amazon Web Services account, Region, and state machine for 90 days. For more information, see Limits Related to State Machine Executions in the Step Functions Developer Guide.

If you don't provide a name for the execution, Step Functions automatically generates a universally unique identifier (UUID) as the execution name.

A name must not contain:

  • white space

  • brackets < > { } [ ]

  • wildcard characters ? *

  • special characters \" # % \\ ^ | ~ ` $ & , ; : /

  • control characters (U+0000-001F, U+007F-009F)

To enable logging with CloudWatch Logs, the name should only contain 0-9, A-Z, a-z, - and _.

" - }, - "input":{ - "shape":"SensitiveData", - "documentation":"

The string that contains the JSON input data for the execution, for example:

\"input\": \"{\\\"first_name\\\" : \\\"test\\\"}\"

If you don't include any JSON input data, you still must include the two braces, for example: \"input\": \"{}\"

Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "traceHeader":{ - "shape":"TraceHeader", - "documentation":"

Passes the X-Ray trace header. The trace header can also be passed in the request payload.

" - } - } - }, - "StartExecutionOutput":{ - "type":"structure", - "required":[ - "executionArn", - "startDate" - ], - "members":{ - "executionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies the execution.

" - }, - "startDate":{ - "shape":"Timestamp", - "documentation":"

The date the execution is started.

" - } - } - }, - "StartSyncExecutionInput":{ - "type":"structure", - "required":["stateMachineArn"], - "members":{ - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine to execute.

" - }, - "name":{ - "shape":"Name", - "documentation":"

The name of the execution.

" - }, - "input":{ - "shape":"SensitiveData", - "documentation":"

The string that contains the JSON input data for the execution, for example:

\"input\": \"{\\\"first_name\\\" : \\\"test\\\"}\"

If you don't include any JSON input data, you still must include the two braces, for example: \"input\": \"{}\"

Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "traceHeader":{ - "shape":"TraceHeader", - "documentation":"

Passes the X-Ray trace header. The trace header can also be passed in the request payload.

" - }, - "includedData":{ - "shape":"IncludedData", - "documentation":"

If your state machine definition is encrypted with a KMS key, callers must have kms:Decrypt permission to decrypt the definition. Alternatively, you can call the API with includedData = METADATA_ONLY to get a successful response without the encrypted definition.

" - } - } - }, - "StartSyncExecutionOutput":{ - "type":"structure", - "required":[ - "executionArn", - "startDate", - "stopDate", - "status" - ], - "members":{ - "executionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies the execution.

" - }, - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies the state machine.

" - }, - "name":{ - "shape":"Name", - "documentation":"

The name of the execution.

" - }, - "startDate":{ - "shape":"Timestamp", - "documentation":"

The date the execution is started.

" - }, - "stopDate":{ - "shape":"Timestamp", - "documentation":"

If the execution has already ended, the date the execution stopped.

" - }, - "status":{ - "shape":"SyncExecutionStatus", - "documentation":"

The current status of the execution.

" - }, - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - }, - "input":{ - "shape":"SensitiveData", - "documentation":"

The string that contains the JSON input data of the execution. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "inputDetails":{"shape":"CloudWatchEventsExecutionDataDetails"}, - "output":{ - "shape":"SensitiveData", - "documentation":"

The JSON output data of the execution. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

This field is set only if the execution succeeds. If the execution fails, this field is null.

" - }, - "outputDetails":{"shape":"CloudWatchEventsExecutionDataDetails"}, - "traceHeader":{ - "shape":"TraceHeader", - "documentation":"

The X-Ray trace header that was passed to the execution.

" - }, - "billingDetails":{ - "shape":"BillingDetails", - "documentation":"

An object that describes workflow billing details, including billed duration and memory use.

" - } - } - }, - "StateEnteredEventDetails":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"Name", - "documentation":"

The name of the state.

" - }, - "input":{ - "shape":"SensitiveData", - "documentation":"

The string that contains the JSON input data for the state. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "inputDetails":{ - "shape":"HistoryEventExecutionDataDetails", - "documentation":"

Contains details about the input for an execution history event.

" - } - }, - "documentation":"

Contains details about a state entered during an execution.

" - }, - "StateExitedEventDetails":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"Name", - "documentation":"

The name of the state.

A name must not contain:

  • white space

  • brackets < > { } [ ]

  • wildcard characters ? *

  • special characters \" # % \\ ^ | ~ ` $ & , ; : /

  • control characters (U+0000-001F, U+007F-009F)

To enable logging with CloudWatch Logs, the name should only contain 0-9, A-Z, a-z, - and _.

" - }, - "output":{ - "shape":"SensitiveData", - "documentation":"

The JSON output data of the state. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "outputDetails":{ - "shape":"HistoryEventExecutionDataDetails", - "documentation":"

Contains details about the output of an execution history event.

" - }, - "assignedVariables":{ - "shape":"AssignedVariables", - "documentation":"

Map of variable name and value as a serialized JSON representation.

" - }, - "assignedVariablesDetails":{ - "shape":"AssignedVariablesDetails", - "documentation":"

Provides details about input or output in an execution history event.

" - } - }, - "documentation":"

Contains details about an exit from a state during an execution.

" - }, - "StateMachineAliasList":{ - "type":"list", - "member":{"shape":"StateMachineAliasListItem"} - }, - "StateMachineAliasListItem":{ - "type":"structure", - "required":[ - "stateMachineAliasArn", - "creationDate" - ], - "members":{ - "stateMachineAliasArn":{ - "shape":"LongArn", - "documentation":"

The Amazon Resource Name (ARN) that identifies a state machine alias. The alias ARN is a combination of state machine ARN and the alias name separated by a colon (:). For example, stateMachineARN:PROD.

" - }, - "creationDate":{ - "shape":"Timestamp", - "documentation":"

The creation date of a state machine alias.

" - } - }, - "documentation":"

Contains details about a specific state machine alias.

" - }, - "StateMachineAlreadyExists":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

A state machine with the same name but a different definition or role ARN already exists.

", - "exception":true - }, - "StateMachineDeleting":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The specified state machine is being deleted.

", - "exception":true - }, - "StateMachineDoesNotExist":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The specified state machine does not exist.

", - "exception":true - }, - "StateMachineLimitExceeded":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The maximum number of state machines has been reached. Existing state machines must be deleted before a new state machine can be created.

", - "exception":true - }, - "StateMachineList":{ - "type":"list", - "member":{"shape":"StateMachineListItem"} - }, - "StateMachineListItem":{ - "type":"structure", - "required":[ - "stateMachineArn", - "name", - "type", - "creationDate" - ], - "members":{ - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) that identifies the state machine.

" - }, - "name":{ - "shape":"Name", - "documentation":"

The name of the state machine.

A name must not contain:

  • white space

  • brackets < > { } [ ]

  • wildcard characters ? *

  • special characters \" # % \\ ^ | ~ ` $ & , ; : /

  • control characters (U+0000-001F, U+007F-009F)

To enable logging with CloudWatch Logs, the name should only contain 0-9, A-Z, a-z, - and _.

" - }, - "type":{ - "shape":"StateMachineType", - "documentation":"

" - }, - "creationDate":{ - "shape":"Timestamp", - "documentation":"

The date the state machine is created.

" - } - }, - "documentation":"

Contains details about the state machine.

" - }, - "StateMachineStatus":{ - "type":"string", - "enum":[ - "ACTIVE", - "DELETING" - ] - }, - "StateMachineType":{ - "type":"string", - "enum":[ - "STANDARD", - "EXPRESS" - ] - }, - "StateMachineTypeNotSupported":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

State machine type is not supported.

", - "exception":true - }, - "StateMachineVersionList":{ - "type":"list", - "member":{"shape":"StateMachineVersionListItem"} - }, - "StateMachineVersionListItem":{ - "type":"structure", - "required":[ - "stateMachineVersionArn", - "creationDate" - ], - "members":{ - "stateMachineVersionArn":{ - "shape":"LongArn", - "documentation":"

The Amazon Resource Name (ARN) that identifies a state machine version. The version ARN is a combination of state machine ARN and the version number separated by a colon (:). For example, stateMachineARN:1.

" - }, - "creationDate":{ - "shape":"Timestamp", - "documentation":"

The creation date of a state machine version.

" - } - }, - "documentation":"

Contains details about a specific state machine version.

" - }, - "StateName":{ - "type":"string", - "max":80, - "min":1 - }, - "StopExecutionInput":{ - "type":"structure", - "required":["executionArn"], - "members":{ - "executionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the execution to stop.

" - }, - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - } - } - }, - "StopExecutionOutput":{ - "type":"structure", - "required":["stopDate"], - "members":{ - "stopDate":{ - "shape":"Timestamp", - "documentation":"

The date the execution is stopped.

" - } - } - }, - "SyncExecutionStatus":{ - "type":"string", - "enum":[ - "SUCCEEDED", - "FAILED", - "TIMED_OUT" - ] - }, - "Tag":{ - "type":"structure", - "members":{ - "key":{ - "shape":"TagKey", - "documentation":"

The key of a tag.

" - }, - "value":{ - "shape":"TagValue", - "documentation":"

The value of a tag.

" - } - }, - "documentation":"

Tags are key-value pairs that can be associated with Step Functions state machines and activities.

An array of key-value pairs. For more information, see Using Cost Allocation Tags in the Amazon Web Services Billing and Cost Management User Guide, and Controlling Access Using IAM Tags.

Tags may only contain Unicode letters, digits, white space, or these symbols: _ . : / = + - @.

" - }, - "TagKey":{ - "type":"string", - "max":128, - "min":1 - }, - "TagKeyList":{ - "type":"list", - "member":{"shape":"TagKey"} - }, - "TagList":{ - "type":"list", - "member":{"shape":"Tag"} - }, - "TagResourceInput":{ - "type":"structure", - "required":[ - "resourceArn", - "tags" - ], - "members":{ - "resourceArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) for the Step Functions state machine or activity.

" - }, - "tags":{ - "shape":"TagList", - "documentation":"

The list of tags to add to a resource.

Tags may only contain Unicode letters, digits, white space, or these symbols: _ . : / = + - @.

" - } - } - }, - "TagResourceOutput":{ - "type":"structure", - "members":{ - } - }, - "TagValue":{ - "type":"string", - "max":256, - "min":0 - }, - "TaskCredentials":{ - "type":"structure", - "members":{ - "roleArn":{ - "shape":"LongArn", - "documentation":"

The ARN of an IAM role that Step Functions assumes for the task. The role can allow cross-account access to resources.

" - } - }, - "documentation":"

Contains details about the credentials that Step Functions uses for a task.

" - }, - "TaskDoesNotExist":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The activity does not exist.

", - "exception":true - }, - "TaskFailedEventDetails":{ - "type":"structure", - "required":[ - "resourceType", - "resource" - ], - "members":{ - "resourceType":{ - "shape":"Name", - "documentation":"

The service name of the resource in a task state.

" - }, - "resource":{ - "shape":"Name", - "documentation":"

The action of the resource called by a task state.

" - }, - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - } - }, - "documentation":"

Contains details about a task failure event.

" - }, - "TaskScheduledEventDetails":{ - "type":"structure", - "required":[ - "resourceType", - "resource", - "region", - "parameters" - ], - "members":{ - "resourceType":{ - "shape":"Name", - "documentation":"

The service name of the resource in a task state.

" - }, - "resource":{ - "shape":"Name", - "documentation":"

The action of the resource called by a task state.

" - }, - "region":{ - "shape":"Name", - "documentation":"

The region of the scheduled task

" - }, - "parameters":{ - "shape":"ConnectorParameters", - "documentation":"

The JSON data passed to the resource referenced in a task state. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "timeoutInSeconds":{ - "shape":"TimeoutInSeconds", - "documentation":"

The maximum allowed duration of the task.

", - "box":true - }, - "heartbeatInSeconds":{ - "shape":"TimeoutInSeconds", - "documentation":"

The maximum allowed duration between two heartbeats for the task.

", - "box":true - }, - "taskCredentials":{ - "shape":"TaskCredentials", - "documentation":"

The credentials that Step Functions uses for the task.

" - } - }, - "documentation":"

Contains details about a task scheduled during an execution.

" - }, - "TaskStartFailedEventDetails":{ - "type":"structure", - "required":[ - "resourceType", - "resource" - ], - "members":{ - "resourceType":{ - "shape":"Name", - "documentation":"

The service name of the resource in a task state.

" - }, - "resource":{ - "shape":"Name", - "documentation":"

The action of the resource called by a task state.

" - }, - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - } - }, - "documentation":"

Contains details about a task that failed to start during an execution.

" - }, - "TaskStartedEventDetails":{ - "type":"structure", - "required":[ - "resourceType", - "resource" - ], - "members":{ - "resourceType":{ - "shape":"Name", - "documentation":"

The service name of the resource in a task state.

" - }, - "resource":{ - "shape":"Name", - "documentation":"

The action of the resource called by a task state.

" - } - }, - "documentation":"

Contains details about the start of a task during an execution.

" - }, - "TaskSubmitFailedEventDetails":{ - "type":"structure", - "required":[ - "resourceType", - "resource" - ], - "members":{ - "resourceType":{ - "shape":"Name", - "documentation":"

The service name of the resource in a task state.

" - }, - "resource":{ - "shape":"Name", - "documentation":"

The action of the resource called by a task state.

" - }, - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - } - }, - "documentation":"

Contains details about a task that failed to submit during an execution.

" - }, - "TaskSubmittedEventDetails":{ - "type":"structure", - "required":[ - "resourceType", - "resource" - ], - "members":{ - "resourceType":{ - "shape":"Name", - "documentation":"

The service name of the resource in a task state.

" - }, - "resource":{ - "shape":"Name", - "documentation":"

The action of the resource called by a task state.

" - }, - "output":{ - "shape":"SensitiveData", - "documentation":"

The response from a resource when a task has started. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "outputDetails":{ - "shape":"HistoryEventExecutionDataDetails", - "documentation":"

Contains details about the output of an execution history event.

" - } - }, - "documentation":"

Contains details about a task submitted to a resource .

" - }, - "TaskSucceededEventDetails":{ - "type":"structure", - "required":[ - "resourceType", - "resource" - ], - "members":{ - "resourceType":{ - "shape":"Name", - "documentation":"

The service name of the resource in a task state.

" - }, - "resource":{ - "shape":"Name", - "documentation":"

The action of the resource called by a task state.

" - }, - "output":{ - "shape":"SensitiveData", - "documentation":"

The full JSON response from a resource when a task has succeeded. This response becomes the output of the related task. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "outputDetails":{ - "shape":"HistoryEventExecutionDataDetails", - "documentation":"

Contains details about the output of an execution history event.

" - } - }, - "documentation":"

Contains details about the successful completion of a task state.

" - }, - "TaskTimedOut":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"} - }, - "documentation":"

The task token has either expired or the task associated with the token has already been closed.

", - "exception":true - }, - "TaskTimedOutEventDetails":{ - "type":"structure", - "required":[ - "resourceType", - "resource" - ], - "members":{ - "resourceType":{ - "shape":"Name", - "documentation":"

The service name of the resource in a task state.

" - }, - "resource":{ - "shape":"Name", - "documentation":"

The action of the resource called by a task state.

" - }, - "error":{ - "shape":"SensitiveError", - "documentation":"

The error code of the failure.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A more detailed explanation of the cause of the failure.

" - } - }, - "documentation":"

Contains details about a resource timeout that occurred during an execution.

" - }, - "TaskToken":{ - "type":"string", - "max":2048, - "min":1 - }, - "TestExecutionStatus":{ - "type":"string", - "enum":[ - "SUCCEEDED", - "FAILED", - "RETRIABLE", - "CAUGHT_ERROR" - ] - }, - "TestStateInput":{ - "type":"structure", - "required":["definition"], - "members":{ - "definition":{ - "shape":"Definition", - "documentation":"

The Amazon States Language (ASL) definition of the state.

" - }, - "roleArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the execution role with the required IAM permissions for the state.

" - }, - "input":{ - "shape":"SensitiveData", - "documentation":"

A string that contains the JSON input data for the state.

" - }, - "inspectionLevel":{ - "shape":"InspectionLevel", - "documentation":"

Determines the values to return when a state is tested. You can specify one of the following types:

  • INFO: Shows the final state output. By default, Step Functions sets inspectionLevel to INFO if you don't specify a level.

  • DEBUG: Shows the final state output along with the input and output data processing result.

  • TRACE: Shows the HTTP request and response for an HTTP Task. This level also shows the final state output along with the input and output data processing result.

Each of these levels also provide information about the status of the state execution and the next state to transition to.

" - }, - "revealSecrets":{ - "shape":"RevealSecrets", - "documentation":"

Specifies whether or not to include secret information in the test result. For HTTP Tasks, a secret includes the data that an EventBridge connection adds to modify the HTTP request headers, query parameters, and body. Step Functions doesn't omit any information included in the state definition or the HTTP response.

If you set revealSecrets to true, you must make sure that the IAM user that calls the TestState API has permission for the states:RevealSecrets action. For an example of IAM policy that sets the states:RevealSecrets permission, see IAM permissions to test a state. Without this permission, Step Functions throws an access denied error.

By default, revealSecrets is set to false.

" - }, - "variables":{ - "shape":"SensitiveData", - "documentation":"

JSON object literal that sets variables used in the state under test. Object keys are the variable names and values are the variable values.

" - } - } - }, - "TestStateOutput":{ - "type":"structure", - "members":{ - "output":{ - "shape":"SensitiveData", - "documentation":"

The JSON output data of the state. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding.

" - }, - "error":{ - "shape":"SensitiveError", - "documentation":"

The error returned when the execution of a state fails.

" - }, - "cause":{ - "shape":"SensitiveCause", - "documentation":"

A detailed explanation of the cause for the error when the execution of a state fails.

" - }, - "inspectionData":{ - "shape":"InspectionData", - "documentation":"

Returns additional details about the state's execution, including its input and output data processing flow, and HTTP request and response information. The inspectionLevel request parameter specifies which details are returned.

" - }, - "nextState":{ - "shape":"StateName", - "documentation":"

The name of the next state to transition to. If you haven't defined a next state in your definition or if the execution of the state fails, this field doesn't contain a value.

" - }, - "status":{ - "shape":"TestExecutionStatus", - "documentation":"

The execution status of the state.

" - } - } - }, - "TimeoutInSeconds":{"type":"long"}, - "Timestamp":{"type":"timestamp"}, - "ToleratedFailureCount":{ - "type":"long", - "min":0 - }, - "ToleratedFailurePercentage":{ - "type":"float", - "max":100, - "min":0 - }, - "TooManyTags":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"}, - "resourceName":{"shape":"Arn"} - }, - "documentation":"

You've exceeded the number of tags allowed for a resource. See the Limits Topic in the Step Functions Developer Guide.

", - "exception":true - }, - "TraceHeader":{ - "type":"string", - "max":256, - "min":0, - "pattern":"\\p{ASCII}*" - }, - "TracingConfiguration":{ - "type":"structure", - "members":{ - "enabled":{ - "shape":"Enabled", - "documentation":"

When set to true, X-Ray tracing is enabled.

" - } - }, - "documentation":"

Selects whether or not the state machine's X-Ray tracing is enabled. Default is false

" - }, - "URL":{"type":"string"}, - "UnsignedInteger":{ - "type":"integer", - "min":0 - }, - "UnsignedLong":{ - "type":"long", - "min":0 - }, - "UntagResourceInput":{ - "type":"structure", - "required":[ - "resourceArn", - "tagKeys" - ], - "members":{ - "resourceArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) for the Step Functions state machine or activity.

" - }, - "tagKeys":{ - "shape":"TagKeyList", - "documentation":"

The list of tags to remove from the resource.

" - } - } - }, - "UntagResourceOutput":{ - "type":"structure", - "members":{ - } - }, - "UpdateMapRunInput":{ - "type":"structure", - "required":["mapRunArn"], - "members":{ - "mapRunArn":{ - "shape":"LongArn", - "documentation":"

The Amazon Resource Name (ARN) of a Map Run.

" - }, - "maxConcurrency":{ - "shape":"MaxConcurrency", - "documentation":"

The maximum number of child workflow executions that can be specified to run in parallel for the Map Run at the same time.

", - "box":true - }, - "toleratedFailurePercentage":{ - "shape":"ToleratedFailurePercentage", - "documentation":"

The maximum percentage of failed items before the Map Run fails.

", - "box":true - }, - "toleratedFailureCount":{ - "shape":"ToleratedFailureCount", - "documentation":"

The maximum number of failed items before the Map Run fails.

", - "box":true - } - } - }, - "UpdateMapRunOutput":{ - "type":"structure", - "members":{ - } - }, - "UpdateStateMachineAliasInput":{ - "type":"structure", - "required":["stateMachineAliasArn"], - "members":{ - "stateMachineAliasArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine alias.

" - }, - "description":{ - "shape":"AliasDescription", - "documentation":"

A description of the state machine alias.

" - }, - "routingConfiguration":{ - "shape":"RoutingConfigurationList", - "documentation":"

The routing configuration of the state machine alias.

An array of RoutingConfig objects that specifies up to two state machine versions that the alias starts executions for.

" - } - } - }, - "UpdateStateMachineAliasOutput":{ - "type":"structure", - "required":["updateDate"], - "members":{ - "updateDate":{ - "shape":"Timestamp", - "documentation":"

The date and time the state machine alias was updated.

" - } - } - }, - "UpdateStateMachineInput":{ - "type":"structure", - "required":["stateMachineArn"], - "members":{ - "stateMachineArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the state machine.

" - }, - "definition":{ - "shape":"Definition", - "documentation":"

The Amazon States Language definition of the state machine. See Amazon States Language.

" - }, - "roleArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the IAM role of the state machine.

" - }, - "loggingConfiguration":{ - "shape":"LoggingConfiguration", - "documentation":"

Use the LoggingConfiguration data type to set CloudWatch Logs options.

" - }, - "tracingConfiguration":{ - "shape":"TracingConfiguration", - "documentation":"

Selects whether X-Ray tracing is enabled.

" - }, - "publish":{ - "shape":"Publish", - "documentation":"

Specifies whether the state machine version is published. The default is false. To publish a version after updating the state machine, set publish to true.

" - }, - "versionDescription":{ - "shape":"VersionDescription", - "documentation":"

An optional description of the state machine version to publish.

You can only specify the versionDescription parameter if you've set publish to true.

" - }, - "encryptionConfiguration":{ - "shape":"EncryptionConfiguration", - "documentation":"

Settings to configure server-side encryption.

" - } - } - }, - "UpdateStateMachineOutput":{ - "type":"structure", - "required":["updateDate"], - "members":{ - "updateDate":{ - "shape":"Timestamp", - "documentation":"

The date and time the state machine was updated.

" - }, - "revisionId":{ - "shape":"RevisionId", - "documentation":"

The revision identifier for the updated state machine.

" - }, - "stateMachineVersionArn":{ - "shape":"Arn", - "documentation":"

The Amazon Resource Name (ARN) of the published state machine version.

If the publish parameter isn't set to true, this field returns null.

" - } - } - }, - "ValidateStateMachineDefinitionCode":{ - "type":"string", - "sensitive":true - }, - "ValidateStateMachineDefinitionDiagnostic":{ - "type":"structure", - "required":[ - "severity", - "code", - "message" - ], - "members":{ - "severity":{ - "shape":"ValidateStateMachineDefinitionSeverity", - "documentation":"

A value of ERROR means that you cannot create or update a state machine with this definition.

WARNING level diagnostics alert you to potential issues, but they will not prevent you from creating or updating your state machine.

" - }, - "code":{ - "shape":"ValidateStateMachineDefinitionCode", - "documentation":"

Identifying code for the diagnostic.

" - }, - "message":{ - "shape":"ValidateStateMachineDefinitionMessage", - "documentation":"

Message describing the diagnostic condition.

" - }, - "location":{ - "shape":"ValidateStateMachineDefinitionLocation", - "documentation":"

Location of the issue in the state machine, if available.

For errors specific to a field, the location could be in the format: /States/<StateName>/<FieldName>, for example: /States/FailState/ErrorPath.

" - } - }, - "documentation":"

Describes potential issues found during state machine validation. Rather than raise an exception, validation will return a list of diagnostic elements containing diagnostic information.

The ValidateStateMachineDefinitionlAPI might add new diagnostics in the future, adjust diagnostic codes, or change the message wording. Your automated processes should only rely on the value of the result field value (OK, FAIL). Do not rely on the exact order, count, or wording of diagnostic messages.

List of warning codes

NO_DOLLAR

No .$ on a field that appears to be a JSONPath or Intrinsic Function.

NO_PATH

Field value looks like a path, but field name does not end with 'Path'.

PASS_RESULT_IS_STATIC

Attempt to use a path in the result of a pass state.

List of error codes

INVALID_JSON_DESCRIPTION

JSON syntax problem found.

MISSING_DESCRIPTION

Received a null or empty workflow input.

SCHEMA_VALIDATION_FAILED

Schema validation reported errors.

INVALID_RESOURCE

The value of a Task-state resource field is invalid.

MISSING_END_STATE

The workflow does not have a terminal state.

DUPLICATE_STATE_NAME

The same state name appears more than once.

INVALID_STATE_NAME

The state name does not follow the naming convention.

STATE_MACHINE_NAME_EMPTY

The state machine name has not been specified.

STATE_MACHINE_NAME_INVALID

The state machine name does not follow the naming convention.

STATE_MACHINE_NAME_TOO_LONG

The state name exceeds the allowed length.

STATE_MACHINE_NAME_ALREADY_EXISTS

The state name already exists.

DUPLICATE_LABEL_NAME

A label name appears more than once.

INVALID_LABEL_NAME

You have provided an invalid label name.

MISSING_TRANSITION_TARGET

The value of \"Next\" field doesn't match a known state name.

TOO_DEEPLY_NESTED

The states are too deeply nested.

" - }, - "ValidateStateMachineDefinitionDiagnosticList":{ - "type":"list", - "member":{"shape":"ValidateStateMachineDefinitionDiagnostic"} - }, - "ValidateStateMachineDefinitionInput":{ - "type":"structure", - "required":["definition"], - "members":{ - "definition":{ - "shape":"Definition", - "documentation":"

The Amazon States Language definition of the state machine. For more information, see Amazon States Language (ASL).

" - }, - "type":{ - "shape":"StateMachineType", - "documentation":"

The target type of state machine for this definition. The default is STANDARD.

" - }, - "severity":{ - "shape":"ValidateStateMachineDefinitionSeverity", - "documentation":"

Minimum level of diagnostics to return. ERROR returns only ERROR diagnostics, whereas WARNING returns both WARNING and ERROR diagnostics. The default is ERROR.

" - }, - "maxResults":{ - "shape":"ValidateStateMachineDefinitionMaxResult", - "documentation":"

The maximum number of diagnostics that are returned per call. The default and maximum value is 100. Setting the value to 0 will also use the default of 100.

If the number of diagnostics returned in the response exceeds maxResults, the value of the truncated field in the response will be set to true.

" - } - } - }, - "ValidateStateMachineDefinitionLocation":{ - "type":"string", - "sensitive":true - }, - "ValidateStateMachineDefinitionMaxResult":{ - "type":"integer", - "max":100, - "min":0 - }, - "ValidateStateMachineDefinitionMessage":{ - "type":"string", - "sensitive":true - }, - "ValidateStateMachineDefinitionOutput":{ - "type":"structure", - "required":[ - "result", - "diagnostics" - ], - "members":{ - "result":{ - "shape":"ValidateStateMachineDefinitionResultCode", - "documentation":"

The result value will be OK when no syntax errors are found, or FAIL if the workflow definition does not pass verification.

" - }, - "diagnostics":{ - "shape":"ValidateStateMachineDefinitionDiagnosticList", - "documentation":"

An array of diagnostic errors and warnings found during validation of the state machine definition. Since warnings do not prevent deploying your workflow definition, the result value could be OK even when warning diagnostics are present in the response.

" - }, - "truncated":{ - "shape":"ValidateStateMachineDefinitionTruncated", - "documentation":"

The result value will be true if the number of diagnostics found in the workflow definition exceeds maxResults. When all diagnostics results are returned, the value will be false.

" - } - } - }, - "ValidateStateMachineDefinitionResultCode":{ - "type":"string", - "enum":[ - "OK", - "FAIL" - ] - }, - "ValidateStateMachineDefinitionSeverity":{ - "type":"string", - "enum":[ - "ERROR", - "WARNING" - ] - }, - "ValidateStateMachineDefinitionTruncated":{ - "type":"boolean", - "box":true - }, - "ValidationException":{ - "type":"structure", - "members":{ - "message":{"shape":"ErrorMessage"}, - "reason":{ - "shape":"ValidationExceptionReason", - "documentation":"

The input does not satisfy the constraints specified by an Amazon Web Services service.

" - } - }, - "documentation":"

The input does not satisfy the constraints specified by an Amazon Web Services service.

", - "exception":true - }, - "ValidationExceptionReason":{ - "type":"string", - "enum":[ - "API_DOES_NOT_SUPPORT_LABELED_ARNS", - "MISSING_REQUIRED_PARAMETER", - "CANNOT_UPDATE_COMPLETED_MAP_RUN", - "INVALID_ROUTING_CONFIGURATION" - ] - }, - "VariableName":{ - "type":"string", - "sensitive":true - }, - "VariableNameList":{ - "type":"list", - "member":{"shape":"VariableName"} - }, - "VariableReferences":{ - "type":"map", - "key":{"shape":"StateName"}, - "value":{"shape":"VariableNameList"}, - "sensitive":true - }, - "VariableValue":{ - "type":"string", - "sensitive":true - }, - "VersionDescription":{ - "type":"string", - "max":256, - "sensitive":true - }, - "VersionWeight":{ - "type":"integer", - "max":100, - "min":0 - }, - "includedDetails":{"type":"boolean"}, - "truncated":{"type":"boolean"} - }, - "documentation":"Step Functions

Step Functions coordinates the components of distributed applications and microservices using visual workflows.

You can use Step Functions to build applications from individual components, each of which performs a discrete function, or task, allowing you to scale and change applications quickly. Step Functions provides a console that helps visualize the components of your application as a series of steps. Step Functions automatically triggers and tracks each step, and retries steps when there are errors, so your application executes predictably and in the right order every time. Step Functions logs the state of each step, so you can quickly diagnose and debug any issues.

Step Functions manages operations and underlying infrastructure to ensure your application is available at any scale. You can run tasks on Amazon Web Services, your own servers, or any system that has access to Amazon Web Services. You can access and use Step Functions using the console, the Amazon Web Services SDKs, or an HTTP API. For more information about Step Functions, see the Step Functions Developer Guide .

If you use the Step Functions API actions using Amazon Web Services SDK integrations, make sure the API actions are in camel case and parameter names are in Pascal case. For example, you could use Step Functions API action startSyncExecution and specify its parameter as StateMachineArn.

" -} From e5aa33db4befd9bb76720c7e75c72e862a168926 Mon Sep 17 00:00:00 2001 From: Daniel Fangl Date: Tue, 26 Nov 2024 19:00:58 +0100 Subject: [PATCH 11/38] Apply IAM patches when loading STS to avoid wrong access key formats (#11931) --- .../localstack/services/iam/iam_patches.py | 120 +++++++++++++++ .../localstack/services/iam/provider.py | 139 +----------------- .../localstack/services/sts/provider.py | 4 + tests/aws/services/iam/test_iam.py | 2 +- 4 files changed, 128 insertions(+), 137 deletions(-) create mode 100644 localstack-core/localstack/services/iam/iam_patches.py diff --git a/localstack-core/localstack/services/iam/iam_patches.py b/localstack-core/localstack/services/iam/iam_patches.py new file mode 100644 index 0000000000000..5e5c9f5f4448f --- /dev/null +++ b/localstack-core/localstack/services/iam/iam_patches.py @@ -0,0 +1,120 @@ +import threading +from typing import Optional + +from moto.iam.models import ( + AccessKey, + AWSManagedPolicy, + IAMBackend, + InlinePolicy, + Policy, +) +from moto.iam.models import Role as MotoRole +from moto.iam.policy_validation import VALID_STATEMENT_ELEMENTS + +from localstack import config +from localstack.utils.patch import patch + +ADDITIONAL_MANAGED_POLICIES = { + "AWSLambdaExecute": { + "Arn": "arn:aws:iam::aws:policy/AWSLambdaExecute", + "Path": "/", + "CreateDate": "2017-10-20T17:23:10+00:00", + "DefaultVersionId": "v4", + "Document": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": ["logs:*"], + "Resource": "arn:aws:logs:*:*:*", + }, + { + "Effect": "Allow", + "Action": ["s3:GetObject", "s3:PutObject"], + "Resource": "arn:aws:s3:::*", + }, + ], + }, + "UpdateDate": "2019-05-20T18:22:18+00:00", + } +} + +IAM_PATCHED = False +IAM_PATCH_LOCK = threading.RLock() + + +def apply_iam_patches(): + global IAM_PATCHED + + # prevent patching multiple times, as this is called from both STS and IAM (for now) + with IAM_PATCH_LOCK: + if IAM_PATCHED: + return + + IAM_PATCHED = True + + # support service linked roles + moto_role_og_arn_prop = MotoRole.arn + + @property + def moto_role_arn(self): + return getattr(self, "service_linked_role_arn", None) or moto_role_og_arn_prop.__get__(self) + + MotoRole.arn = moto_role_arn + + # Add missing managed polices + # TODO this might not be necessary + @patch(IAMBackend._init_aws_policies) + def _init_aws_policies_extended(_init_aws_policies, self): + loaded_policies = _init_aws_policies(self) + loaded_policies.extend( + [ + AWSManagedPolicy.from_data(name, self.account_id, self.region_name, d) + for name, d in ADDITIONAL_MANAGED_POLICIES.items() + ] + ) + return loaded_policies + + if "Principal" not in VALID_STATEMENT_ELEMENTS: + VALID_STATEMENT_ELEMENTS.append("Principal") + + # patch policy __init__ to set document as attribute + + @patch(Policy.__init__) + def policy__init__( + fn, + self, + name, + account_id, + region, + default_version_id=None, + description=None, + document=None, + **kwargs, + ): + fn(self, name, account_id, region, default_version_id, description, document, **kwargs) + self.document = document + + # patch unapply_policy + + @patch(InlinePolicy.unapply_policy) + def inline_policy_unapply_policy(fn, self, backend): + try: + fn(self, backend) + except Exception: + # Actually role can be deleted before policy being deleted in cloudformation + pass + + @patch(AccessKey.__init__) + def access_key__init__( + fn, + self, + user_name: Optional[str], + prefix: str, + account_id: str, + status: str = "Active", + **kwargs, + ): + if not config.PARITY_AWS_ACCESS_KEY_ID: + prefix = "L" + prefix[1:] + fn(self, user_name, prefix, account_id, status, **kwargs) diff --git a/localstack-core/localstack/services/iam/provider.py b/localstack-core/localstack/services/iam/provider.py index a4858cc4f0b41..7adca335e82da 100644 --- a/localstack-core/localstack/services/iam/provider.py +++ b/localstack-core/localstack/services/iam/provider.py @@ -1,22 +1,16 @@ import json import re from datetime import datetime -from typing import Dict, List, Optional +from typing import Dict, List from urllib.parse import quote from moto.iam.models import ( - AccessKey, - AWSManagedPolicy, IAMBackend, - InlinePolicy, - Policy, filter_items_with_path_prefix, iam_backends, ) from moto.iam.models import Role as MotoRole -from moto.iam.policy_validation import VALID_STATEMENT_ELEMENTS -from localstack import config from localstack.aws.api import CommonServiceException, RequestContext, handler from localstack.aws.api.iam import ( ActionNameListType, @@ -66,37 +60,13 @@ ) from localstack.aws.connect import connect_to from localstack.constants import INTERNAL_AWS_SECRET_ACCESS_KEY +from localstack.services.iam.iam_patches import apply_iam_patches from localstack.services.moto import call_moto from localstack.utils.aws.request_context import extract_access_key_id_from_auth_header from localstack.utils.common import short_uid -from localstack.utils.patch import patch SERVICE_LINKED_ROLE_PATH_PREFIX = "/aws-service-role" -ADDITIONAL_MANAGED_POLICIES = { - "AWSLambdaExecute": { - "Arn": "arn:aws:iam::aws:policy/AWSLambdaExecute", - "Path": "/", - "CreateDate": "2017-10-20T17:23:10+00:00", - "DefaultVersionId": "v4", - "Document": { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Action": ["logs:*"], - "Resource": "arn:aws:logs:*:*:*", - }, - { - "Effect": "Allow", - "Action": ["s3:GetObject", "s3:PutObject"], - "Resource": "arn:aws:s3:::*", - }, - ], - }, - "UpdateDate": "2019-05-20T18:22:18+00:00", - } -} POLICY_ARN_REGEX = re.compile(r"arn:[^:]+:iam::(?:\d{12}|aws):policy/.*") @@ -107,7 +77,7 @@ def get_iam_backend(context: RequestContext) -> IAMBackend: class IamProvider(IamApi): def __init__(self): - apply_patches() + apply_iam_patches() @handler("CreateRole", expand=False) def create_role( @@ -450,106 +420,3 @@ def attach_user_policy( if not POLICY_ARN_REGEX.match(policy_arn): raise InvalidInputException(f"ARN {policy_arn} is not valid.") return call_moto(context=context) - - # def get_user( - # self, context: RequestContext, user_name: existingUserNameType = None - # ) -> GetUserResponse: - # # TODO: The following migrates patch 'iam_response_get_user' as a provider function. - # # However, there are concerns with utilising 'aws_stack.extract_access_key_id_from_auth_header' - # # in place of 'moto.core.responses.get_current_user'. - # if not user_name: - # access_key_id = aws_stack.extract_access_key_id_from_auth_header(context.request.headers) - # moto_user = moto_iam_backend.get_user_from_access_key_id(access_key_id) - # if moto_user is None: - # moto_user = MotoUser("default_user") - # else: - # moto_user = moto_iam_backend.get_user(user_name) - # - # response_user_name = config.TEST_IAM_USER_NAME or moto_user.name - # response_user_id = config.TEST_IAM_USER_ID or moto_user.id - # moto_user = moto_iam_backend.users.get(response_user_name) or moto_user - # moto_tags = moto_iam_backend.tagger.list_tags_for_resource(moto_user.arn).get("Tags", []) - # response_tags = None - # if moto_tags: - # response_tags = [Tag(Key=t["Key"], Value=t["Value"]) for t in moto_tags] - # - # response_user = User() - # response_user["Path"] = moto_user.path - # response_user["UserName"] = response_user_name - # response_user["UserId"] = response_user_id - # response_user["Arn"] = moto_user.arn - # response_user["CreateDate"] = moto_user.create_date - # if moto_user.password_last_used: - # response_user["PasswordLastUsed"] = moto_user.password_last_used - # # response_user["PermissionsBoundary"] = # TODO - # if response_tags: - # response_user["Tags"] = response_tags - # return GetUserResponse(User=response_user) - - -def apply_patches(): - # support service linked roles - - @property - def moto_role_arn(self): - return getattr(self, "service_linked_role_arn", None) or moto_role_og_arn_prop.__get__(self) - - moto_role_og_arn_prop = MotoRole.arn - MotoRole.arn = moto_role_arn - - # Add missing managed polices - # TODO this might not be necessary - @patch(IAMBackend._init_aws_policies) - def _init_aws_policies_extended(_init_aws_policies, self): - loaded_policies = _init_aws_policies(self) - loaded_policies.extend( - [ - AWSManagedPolicy.from_data(name, self.account_id, self.region_name, d) - for name, d in ADDITIONAL_MANAGED_POLICIES.items() - ] - ) - return loaded_policies - - if "Principal" not in VALID_STATEMENT_ELEMENTS: - VALID_STATEMENT_ELEMENTS.append("Principal") - - # patch policy __init__ to set document as attribute - - @patch(Policy.__init__) - def policy__init__( - fn, - self, - name, - account_id, - region, - default_version_id=None, - description=None, - document=None, - **kwargs, - ): - fn(self, name, account_id, region, default_version_id, description, document, **kwargs) - self.document = document - - # patch unapply_policy - - @patch(InlinePolicy.unapply_policy) - def inline_policy_unapply_policy(fn, self, backend): - try: - fn(self, backend) - except Exception: - # Actually role can be deleted before policy being deleted in cloudformation - pass - - @patch(AccessKey.__init__) - def access_key__init__( - fn, - self, - user_name: Optional[str], - prefix: str, - account_id: str, - status: str = "Active", - **kwargs, - ): - if not config.PARITY_AWS_ACCESS_KEY_ID: - prefix = "L" + prefix[1:] - fn(self, user_name, prefix, account_id, status, **kwargs) diff --git a/localstack-core/localstack/services/sts/provider.py b/localstack-core/localstack/services/sts/provider.py index 90dad64269a77..006a510a612ce 100644 --- a/localstack-core/localstack/services/sts/provider.py +++ b/localstack-core/localstack/services/sts/provider.py @@ -18,6 +18,7 @@ tokenCodeType, unrestrictedSessionPolicyDocumentType, ) +from localstack.services.iam.iam_patches import apply_iam_patches from localstack.services.moto import call_moto from localstack.services.plugins import ServiceLifecycleHook from localstack.services.sts.models import sts_stores @@ -27,6 +28,9 @@ class StsProvider(StsApi, ServiceLifecycleHook): + def __init__(self): + apply_iam_patches() + def get_caller_identity(self, context: RequestContext, **kwargs) -> GetCallerIdentityResponse: response = call_moto(context) if "user/moto" in response["Arn"] and "sts" in response["Arn"]: diff --git a/tests/aws/services/iam/test_iam.py b/tests/aws/services/iam/test_iam.py index cf9913f0de98c..9f1bc02844f7c 100755 --- a/tests/aws/services/iam/test_iam.py +++ b/tests/aws/services/iam/test_iam.py @@ -5,7 +5,7 @@ from botocore.exceptions import ClientError from localstack.aws.api.iam import Tag -from localstack.services.iam.provider import ADDITIONAL_MANAGED_POLICIES +from localstack.services.iam.iam_patches import ADDITIONAL_MANAGED_POLICIES from localstack.testing.aws.util import create_client_with_keys, wait_for_user from localstack.testing.pytest import markers from localstack.utils.aws.arns import get_partition From e9777b7068f19275bfb80e34aaa292b28294a7b4 Mon Sep 17 00:00:00 2001 From: Mathieu Cloutier <79954947+cloutierMat@users.noreply.github.com> Date: Tue, 26 Nov 2024 15:15:27 -0700 Subject: [PATCH 12/38] ci/prevent init file to break packaging (#11914) --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index a78b5e6d54653..76710966bd689 100644 --- a/Makefile +++ b/Makefile @@ -117,6 +117,7 @@ test-coverage: TEST_EXEC = python -m coverage run $(COVERAGE_ARGS) -m test-coverage: test ## Run automated tests and create coverage report lint: ## Run code linter to check code style, check if formatter would make changes and check if dependency pins need to be updated + @[ -f localstack-core/localstack/__init__.py ] && echo "localstack-core/localstack/__init__.py will break packaging." && exit 1 || : ($(VENV_RUN); python -m ruff check --output-format=full . && python -m ruff format --check .) $(VENV_RUN); pre-commit run check-pinned-deps-for-needed-upgrade --files pyproject.toml # run pre-commit hook manually here to ensure that this check runs in CI as well $(VENV_RUN); openapi-spec-validator localstack-core/localstack/openapi.yaml From 9e21cd5764f31a06d262f4b8b5b56ddc3ac4b9ce Mon Sep 17 00:00:00 2001 From: Ben Simon Hartung <42031100+bentsku@users.noreply.github.com> Date: Tue, 26 Nov 2024 23:42:35 +0100 Subject: [PATCH 13/38] add variable to configure SNS sender (#11930) --- localstack-core/localstack/config.py | 3 ++ .../localstack/services/sns/publisher.py | 7 ++- tests/aws/services/sns/test_sns.py | 43 +++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/localstack-core/localstack/config.py b/localstack-core/localstack/config.py index 7fc1dc73cf7dc..58c76cdbdf586 100644 --- a/localstack-core/localstack/config.py +++ b/localstack-core/localstack/config.py @@ -1122,6 +1122,8 @@ def populate_edge_configuration( # Whether to really publish to GCM while using SNS Platform Application (needs credentials) LEGACY_SNS_GCM_PUBLISHING = is_env_true("LEGACY_SNS_GCM_PUBLISHING") +SNS_SES_SENDER_ADDRESS = os.environ.get("SNS_SES_SENDER_ADDRESS", "").strip() + # Whether the Next Gen APIGW invocation logic is enabled (on by default) APIGW_NEXT_GEN_PROVIDER = os.environ.get("PROVIDER_OVERRIDE_APIGATEWAY", "") in ("next_gen", "") @@ -1334,6 +1336,7 @@ def use_custom_dns(): "SNAPSHOT_LOAD_STRATEGY", "SNAPSHOT_SAVE_STRATEGY", "SNAPSHOT_FLUSH_INTERVAL", + "SNS_SES_SENDER_ADDRESS", "SQS_DELAY_PURGE_RETRY", "SQS_DELAY_RECENTLY_DELETED", "SQS_ENABLE_MESSAGE_RETENTION_PERIOD", diff --git a/localstack-core/localstack/services/sns/publisher.py b/localstack-core/localstack/services/sns/publisher.py index 9f1c4f917dbd9..9fc6b4eb5131d 100644 --- a/localstack-core/localstack/services/sns/publisher.py +++ b/localstack-core/localstack/services/sns/publisher.py @@ -569,13 +569,16 @@ def _publish(self, context: SnsPublishContext, subscriber: SnsSubscription): region = extract_region_from_arn(subscriber["Endpoint"]) ses_client = connect_to(aws_access_key_id=account_id, region_name=region).ses if endpoint := subscriber.get("Endpoint"): + # TODO: legacy value, replace by a more sane value in the future + # no-reply@sns-localstack.cloud or similar + sender = config.SNS_SES_SENDER_ADDRESS or "admin@localstack.com" ses_client.verify_email_address(EmailAddress=endpoint) - ses_client.verify_email_address(EmailAddress="admin@localstack.com") + ses_client.verify_email_address(EmailAddress=sender) message_body = self.prepare_message( context.message, subscriber, topic_attributes=context.topic_attributes ) ses_client.send_email( - Source="admin@localstack.com", + Source=sender, Message={ "Body": {"Text": {"Data": message_body}}, "Subject": {"Data": "SNS-Subscriber-Endpoint"}, diff --git a/tests/aws/services/sns/test_sns.py b/tests/aws/services/sns/test_sns.py index 63dbcf12b497a..3043e688a3d16 100644 --- a/tests/aws/services/sns/test_sns.py +++ b/tests/aws/services/sns/test_sns.py @@ -3003,6 +3003,49 @@ def check_subscription(): retry(check_subscription, retries=PUBLICATION_RETRIES, sleep=PUBLICATION_TIMEOUT) + @markers.aws.only_localstack + def test_email_sender( + self, + sns_create_topic, + sns_subscription, + aws_client, + monkeypatch, + ): + # make sure to reset all received emails in SES + requests.delete("http://localhost:4566/_aws/ses") + + topic_arn = sns_create_topic()["TopicArn"] + sns_subscription( + TopicArn=topic_arn, + Protocol="email", + Endpoint="localstack@yopmail.com", + ) + + aws_client.sns.publish( + Message="Test message", + TopicArn=topic_arn, + ) + + def _get_messages(amount: int) -> list[dict]: + response = requests.get("http://localhost:4566/_aws/ses").json() + assert len(response["messages"]) == amount + return response["messages"] + + messages = retry(lambda: _get_messages(1), retries=PUBLICATION_RETRIES, sleep=1) + # legacy default value, should be replaced at some point + assert messages[0]["Source"] == "admin@localstack.com" + requests.delete("http://localhost:4566/_aws/ses") + + sender_address = "no-reply@sns.localstack.cloud" + monkeypatch.setattr(config, "SNS_SES_SENDER_ADDRESS", sender_address) + + aws_client.sns.publish( + Message="Test message", + TopicArn=topic_arn, + ) + messages = retry(lambda: _get_messages(1), retries=PUBLICATION_RETRIES, sleep=1) + assert messages[0]["Source"] == sender_address + class TestSNSPlatformEndpoint: @markers.aws.only_localstack From 221fde160af62984f57c822a8bffec82e1fec1bd Mon Sep 17 00:00:00 2001 From: Mathieu Cloutier <79954947+cloutierMat@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:03:22 -0700 Subject: [PATCH 14/38] Apigw fix openapi identity sources (#11939) --- .../localstack/services/apigateway/helpers.py | 18 +- tests/aws/files/openapi.cognito-auth.json | 84 ++++- .../apigateway/test_apigateway_import.py | 20 +- .../test_apigateway_import.snapshot.json | 347 +++++++++++++++++- .../test_apigateway_import.validation.json | 2 +- 5 files changed, 449 insertions(+), 22 deletions(-) diff --git a/localstack-core/localstack/services/apigateway/helpers.py b/localstack-core/localstack/services/apigateway/helpers.py index 8750da66e3bb0..ddb2c1784f942 100644 --- a/localstack-core/localstack/services/apigateway/helpers.py +++ b/localstack-core/localstack/services/apigateway/helpers.py @@ -4,7 +4,7 @@ import json import logging from datetime import datetime -from typing import List, Optional, Union +from typing import List, Optional, TypedDict, Union from urllib import parse as urlparse from jsonpatch import apply_patch @@ -91,6 +91,11 @@ class OpenAPIExt: TAG_VALUE = "x-amazon-apigateway-tag-value" +class AuthorizerConfig(TypedDict): + authorizer: Authorizer + authorization_scopes: Optional[list[str]] + + # TODO: make the CRUD operations in this file generic for the different model types (authorizes, validators, ...) @@ -564,14 +569,14 @@ def create_authorizers(security_schemes: dict) -> None: authorizers[security_scheme_name] = authorizer - def get_authorizer(path_payload: dict) -> Optional[Authorizer]: + def get_authorizer(path_payload: dict) -> Optional[AuthorizerConfig]: if not (security_schemes := path_payload.get("security")): return None for security_scheme in security_schemes: - for security_scheme_name in security_scheme.keys(): + for security_scheme_name, scopes in security_scheme.items(): if authorizer := authorizers.get(security_scheme_name): - return authorizer + return AuthorizerConfig(authorizer=authorizer, authorization_scopes=scopes) def get_or_create_path(abs_path: str, base_path: str): parts = abs_path.rstrip("/").replace("//", "/").split("/") @@ -815,7 +820,7 @@ def create_method_resource(child, method, method_schema): kwargs = {} if authorizer := get_authorizer(method_schema) or default_authorizer: - method_authorizer = authorizer or default_authorizer + method_authorizer = authorizer["authorizer"] # override the authorizer_type if it's a TOKEN or REQUEST to CUSTOM if (authorizer_type := method_authorizer["type"]) in ("TOKEN", "REQUEST"): authorization_type = "CUSTOM" @@ -824,6 +829,9 @@ def create_method_resource(child, method, method_schema): kwargs["authorizer_id"] = method_authorizer["id"] + if authorization_scopes := authorizer.get("authorization_scopes"): + kwargs["authorization_scopes"] = authorization_scopes + return child.add_method( method, api_key_required=api_key_required, diff --git a/tests/aws/files/openapi.cognito-auth.json b/tests/aws/files/openapi.cognito-auth.json index 7132880092fae..416bf3f274aef 100644 --- a/tests/aws/files/openapi.cognito-auth.json +++ b/tests/aws/files/openapi.cognito-auth.json @@ -6,6 +6,75 @@ "version": "1.0" }, "paths": { + "/default-no-scope": { + "get": { + "security": [ + {"cognito-test-identity-source": []} + ], + "responses": { + "200": { + "description": "200 response" + } + }, + "x-amazon-apigateway-integration": { + "responses": { + "default": { + "statusCode": "200" + } + }, + "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets", + "passthroughBehavior": "when_no_match", + "httpMethod": "GET", + "type": "http" + } + } + }, + "/default-scope-override": { + "get": { + "security": [ + {"cognito-test-identity-source": ["openid"]} + ], + "responses": { + "200": { + "description": "200 response" + } + }, + "x-amazon-apigateway-integration": { + "responses": { + "default": { + "statusCode": "200" + } + }, + "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets", + "passthroughBehavior": "when_no_match", + "httpMethod": "GET", + "type": "http" + } + } + }, + "/non-default-authorizer": { + "get": { + "security": [ + {"extra-test-identity-source": ["email", "openid"]} + ], + "responses": { + "200": { + "description": "200 response" + } + }, + "x-amazon-apigateway-integration": { + "responses": { + "default": { + "statusCode": "200" + } + }, + "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets", + "passthroughBehavior": "when_no_match", + "httpMethod": "GET", + "type": "http" + } + } + }, "/pets": { "get": { "operationId": "GET HTTP", @@ -66,6 +135,18 @@ "${cognito_pool_arn}" ] } + }, + "extra-test-identity-source": { + "type": "apiKey", + "name": "TestHeaderAuth", + "in": "header", + "x-amazon-apigateway-authtype": "cognito_user_pools", + "x-amazon-apigateway-authorizer": { + "type": "cognito_user_pools", + "providerARNs": [ + "${cognito_pool_arn}" + ] + } } }, "schemas": { @@ -93,5 +174,6 @@ } } } - } + }, + "security": [{"cognito-test-identity-source": ["email"]}] } diff --git a/tests/aws/services/apigateway/test_apigateway_import.py b/tests/aws/services/apigateway/test_apigateway_import.py index aa91c51b5be81..3511814e1c101 100644 --- a/tests/aws/services/apigateway/test_apigateway_import.py +++ b/tests/aws/services/apigateway/test_apigateway_import.py @@ -842,6 +842,11 @@ def test_import_with_http_method_integration( apigw_snapshot_imported_resources(rest_api_id=rest_api_id, resources=response) @pytest.mark.no_apigw_snap_transformers + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$.resources.items..resourceMethods.GET", # AWS does not show them after import + ] + ) @markers.aws.validated def test_import_with_cognito_auth_identity_source( self, @@ -856,10 +861,10 @@ def test_import_with_cognito_auth_identity_source( [ snapshot.transform.jsonpath("$.import-swagger.id", value_replacement="rest-id"), snapshot.transform.jsonpath( - "$.import-swagger.rootResourceId", value_replacement="root-resource-id" + "$.resources.items..id", value_replacement="resource-id" ), snapshot.transform.jsonpath( - "$.get-authorizers.items..id", value_replacement="authorizer-id" + "$.get-authorizers..id", value_replacement="authorizer-id" ), ] ) @@ -874,6 +879,13 @@ def test_import_with_cognito_auth_identity_source( rest_api_id = response["id"] - # assert that are no multiple authorizers authorizers = aws_client.apigateway.get_authorizers(restApiId=rest_api_id) - snapshot.match("get-authorizers", authorizers) + snapshot.match("get-authorizers", sorted(authorizers["items"], key=lambda x: x["name"])) + + response = aws_client.apigateway.get_resources(restApiId=rest_api_id) + response["items"] = sorted(response["items"], key=itemgetter("path")) + snapshot.match("resources", response) + + # this fixture will iterate over every resource and match its method, methodResponse, integration and + # integrationResponse + apigw_snapshot_imported_resources(rest_api_id=rest_api_id, resources=response) diff --git a/tests/aws/services/apigateway/test_apigateway_import.snapshot.json b/tests/aws/services/apigateway/test_apigateway_import.snapshot.json index d78cd9cf8699b..c232f286ef439 100644 --- a/tests/aws/services/apigateway/test_apigateway_import.snapshot.json +++ b/tests/aws/services/apigateway/test_apigateway_import.snapshot.json @@ -4810,7 +4810,7 @@ } }, "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_cognito_auth_identity_source": { - "recorded-date": "05-11-2024, 11:37:35", + "recorded-date": "26-11-2024, 21:33:17", "recorded-content": { "import-swagger": { "apiKeySource": "HEADER", @@ -4824,30 +4824,355 @@ }, "id": "", "name": "Example Pet Store", - "rootResourceId": "", + "rootResourceId": "", "version": "1.0", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 201 } }, - "get-authorizers": { + "get-authorizers": [ + { + "id": "", + "name": "cognito-test-identity-source", + "type": "COGNITO_USER_POOLS", + "providerARNs": [ + "arn::cognito-idp::111111111111:userpool/_ABC123" + ], + "authType": "cognito_user_pools", + "identitySource": "method.request.header.TestHeaderAuth" + }, + { + "id": "", + "name": "extra-test-identity-source", + "type": "COGNITO_USER_POOLS", + "providerARNs": [ + "arn::cognito-idp::111111111111:userpool/_ABC123" + ], + "authType": "cognito_user_pools", + "identitySource": "method.request.header.TestHeaderAuth" + } + ], + "resources": { "items": [ { - "authType": "cognito_user_pools", - "id": "", - "identitySource": "method.request.header.TestHeaderAuth", - "name": "cognito-test-identity-source", - "providerARNs": [ - "arn::cognito-idp::111111111111:userpool/_ABC123" - ], - "type": "COGNITO_USER_POOLS" + "id": "", + "path": "/" + }, + { + "id": "", + "parentId": "", + "path": "/default-no-scope", + "pathPart": "default-no-scope", + "resourceMethods": { + "GET": {} + } + }, + { + "id": "", + "parentId": "", + "path": "/default-scope-override", + "pathPart": "default-scope-override", + "resourceMethods": { + "GET": {} + } + }, + { + "id": "", + "parentId": "", + "path": "/non-default-authorizer", + "pathPart": "non-default-authorizer", + "resourceMethods": { + "GET": {} + } + }, + { + "id": "", + "parentId": "", + "path": "/pets", + "pathPart": "pets", + "resourceMethods": { + "GET": {} + } + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "method-default-no-scope-get": { + "apiKeyRequired": false, + "authorizationType": "COGNITO_USER_POOLS", + "authorizerId": "", + "httpMethod": "GET", + "methodIntegration": { + "cacheKeyParameters": [], + "cacheNamespace": "", + "connectionType": "INTERNET", + "httpMethod": "GET", + "integrationResponses": { + "200": { + "statusCode": "200" + } + }, + "passthroughBehavior": "WHEN_NO_MATCH", + "timeoutInMillis": 29000, + "type": "HTTP", + "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets" + }, + "methodResponses": { + "200": { + "statusCode": "200" + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "method-response-default-no-scope-get": { + "statusCode": "200", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "integration-default-no-scope-get": { + "cacheKeyParameters": [], + "cacheNamespace": "", + "connectionType": "INTERNET", + "httpMethod": "GET", + "integrationResponses": { + "200": { + "statusCode": "200" } + }, + "passthroughBehavior": "WHEN_NO_MATCH", + "timeoutInMillis": 29000, + "type": "HTTP", + "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "integration-response-default-no-scope-get": { + "statusCode": "200", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "method-default-scope-override-get": { + "apiKeyRequired": false, + "authorizationScopes": [ + "openid" ], + "authorizationType": "COGNITO_USER_POOLS", + "authorizerId": "", + "httpMethod": "GET", + "methodIntegration": { + "cacheKeyParameters": [], + "cacheNamespace": "", + "connectionType": "INTERNET", + "httpMethod": "GET", + "integrationResponses": { + "200": { + "statusCode": "200" + } + }, + "passthroughBehavior": "WHEN_NO_MATCH", + "timeoutInMillis": 29000, + "type": "HTTP", + "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets" + }, + "methodResponses": { + "200": { + "statusCode": "200" + } + }, "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } + }, + "method-response-default-scope-override-get": { + "statusCode": "200", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "integration-default-scope-override-get": { + "cacheKeyParameters": [], + "cacheNamespace": "", + "connectionType": "INTERNET", + "httpMethod": "GET", + "integrationResponses": { + "200": { + "statusCode": "200" + } + }, + "passthroughBehavior": "WHEN_NO_MATCH", + "timeoutInMillis": 29000, + "type": "HTTP", + "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "integration-response-default-scope-override-get": { + "statusCode": "200", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "method-non-default-authorizer-get": { + "apiKeyRequired": false, + "authorizationScopes": [ + "email", + "openid" + ], + "authorizationType": "COGNITO_USER_POOLS", + "authorizerId": "", + "httpMethod": "GET", + "methodIntegration": { + "cacheKeyParameters": [], + "cacheNamespace": "", + "connectionType": "INTERNET", + "httpMethod": "GET", + "integrationResponses": { + "200": { + "statusCode": "200" + } + }, + "passthroughBehavior": "WHEN_NO_MATCH", + "timeoutInMillis": 29000, + "type": "HTTP", + "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets" + }, + "methodResponses": { + "200": { + "statusCode": "200" + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "method-response-non-default-authorizer-get": { + "statusCode": "200", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "integration-non-default-authorizer-get": { + "cacheKeyParameters": [], + "cacheNamespace": "", + "connectionType": "INTERNET", + "httpMethod": "GET", + "integrationResponses": { + "200": { + "statusCode": "200" + } + }, + "passthroughBehavior": "WHEN_NO_MATCH", + "timeoutInMillis": 29000, + "type": "HTTP", + "uri": "http://petstore-demo-endpoint.execute-api.com/petstore/pets", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "integration-response-non-default-authorizer-get": { + "statusCode": "200", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "method-pets-get": { + "apiKeyRequired": false, + "authorizationScopes": [ + "email" + ], + "authorizationType": "COGNITO_USER_POOLS", + "authorizerId": "", + "httpMethod": "GET", + "methodIntegration": { + "cacheKeyParameters": [], + "cacheNamespace": "", + "connectionType": "INTERNET", + "httpMethod": "GET", + "passthroughBehavior": "WHEN_NO_MATCH", + "timeoutInMillis": 29000, + "type": "HTTP_PROXY", + "uri": "http://petstore.execute-api.us-west-1.amazonaws.com/petstore/pets" + }, + "methodResponses": { + "200": { + "responseModels": { + "application/json": "Pets" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Origin": false + }, + "statusCode": "200" + } + }, + "operationName": "GET HTTP", + "requestParameters": { + "method.request.querystring.page": false, + "method.request.querystring.type": false + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "method-response-pets-get": { + "responseModels": { + "application/json": "Pets" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Origin": false + }, + "statusCode": "200", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "integration-pets-get": { + "cacheKeyParameters": [], + "cacheNamespace": "", + "connectionType": "INTERNET", + "httpMethod": "GET", + "passthroughBehavior": "WHEN_NO_MATCH", + "timeoutInMillis": 29000, + "type": "HTTP_PROXY", + "uri": "http://petstore.execute-api.us-west-1.amazonaws.com/petstore/pets", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "integration-response-pets-get": { + "Error": { + "Code": "NotFoundException", + "Message": "Invalid Response status code specified" + }, + "message": "Invalid Response status code specified", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } } } } diff --git a/tests/aws/services/apigateway/test_apigateway_import.validation.json b/tests/aws/services/apigateway/test_apigateway_import.validation.json index 4ab869f05f123..2b90cde06c2ef 100644 --- a/tests/aws/services/apigateway/test_apigateway_import.validation.json +++ b/tests/aws/services/apigateway/test_apigateway_import.validation.json @@ -36,7 +36,7 @@ "last_validated_date": "2024-04-15T21:37:44+00:00" }, "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_cognito_auth_identity_source": { - "last_validated_date": "2024-11-05T11:37:34+00:00" + "last_validated_date": "2024-11-26T21:33:17+00:00" }, "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_global_api_key_authorizer": { "last_validated_date": "2024-04-15T21:36:29+00:00" From 1adbd94afd5d4115ce59e88273464837146444f4 Mon Sep 17 00:00:00 2001 From: LocalStack Bot <88328844+localstack-bot@users.noreply.github.com> Date: Wed, 27 Nov 2024 09:19:07 +0100 Subject: [PATCH 15/38] Update ASF APIs, update s3 provider signature (#11940) Co-authored-by: LocalStack Bot Co-authored-by: Benjamin Simon --- .../localstack/aws/api/ec2/__init__.py | 36 +++++++++++++++++++ .../localstack/aws/api/s3/__init__.py | 4 +++ .../localstack/services/s3/provider.py | 1 + pyproject.toml | 4 +-- requirements-base-runtime.txt | 4 +-- requirements-dev.txt | 6 ++-- requirements-runtime.txt | 6 ++-- requirements-test.txt | 6 ++-- requirements-typehint.txt | 6 ++-- 9 files changed, 57 insertions(+), 16 deletions(-) diff --git a/localstack-core/localstack/aws/api/ec2/__init__.py b/localstack-core/localstack/aws/api/ec2/__init__.py index 2a95b26d5c82e..61cad487aeed1 100644 --- a/localstack-core/localstack/aws/api/ec2/__init__.py +++ b/localstack-core/localstack/aws/api/ec2/__init__.py @@ -301,6 +301,8 @@ SecurityGroupRuleId = str SensitiveUrl = str SensitiveUserData = str +SnapshotCompletionDurationMinutesRequest = int +SnapshotCompletionDurationMinutesResponse = int SnapshotId = str SpotFleetRequestId = str SpotInstanceRequestId = str @@ -3232,6 +3234,11 @@ class TrafficType(StrEnum): ALL = "ALL" +class TransferType(StrEnum): + time_based = "time-based" + standard = "standard" + + class TransitGatewayAssociationState(StrEnum): associating = "associating" associated = "associated" @@ -5988,6 +5995,7 @@ class ConnectionNotification(TypedDict, total=False): ConnectionNotificationArn: Optional[String] ConnectionEvents: Optional[ValueStringList] ConnectionNotificationState: Optional[ConnectionNotificationState] + ServiceRegion: Optional[String] ConnectionNotificationIdsList = List[ConnectionNotificationId] @@ -6112,6 +6120,7 @@ class CopySnapshotRequest(ServiceRequest): SourceRegion: String SourceSnapshotId: String TagSpecifications: Optional[TagSpecificationList] + CompletionDurationMinutes: Optional[SnapshotCompletionDurationMinutesRequest] DryRun: Optional[Boolean] @@ -9152,6 +9161,7 @@ class CreateVpcEndpointRequest(ServiceRequest): PrivateDnsEnabled: Optional[Boolean] TagSpecifications: Optional[TagSpecificationList] SubnetConfigurations: Optional[SubnetConfigurationsList] + ServiceRegion: Optional[String] class LastError(TypedDict, total=False): @@ -9200,6 +9210,7 @@ class VpcEndpoint(TypedDict, total=False): Tags: Optional[TagList] OwnerId: Optional[String] LastError: Optional[LastError] + ServiceRegion: Optional[String] class CreateVpcEndpointResult(TypedDict, total=False): @@ -9214,10 +9225,19 @@ class CreateVpcEndpointServiceConfigurationRequest(ServiceRequest): NetworkLoadBalancerArns: Optional[ValueStringList] GatewayLoadBalancerArns: Optional[ValueStringList] SupportedIpAddressTypes: Optional[ValueStringList] + SupportedRegions: Optional[ValueStringList] ClientToken: Optional[String] TagSpecifications: Optional[TagSpecificationList] +class SupportedRegionDetail(TypedDict, total=False): + Region: Optional[String] + ServiceState: Optional[String] + + +SupportedRegionSet = List[SupportedRegionDetail] + + class PrivateDnsNameConfiguration(TypedDict, total=False): State: Optional[DnsNameState] Type: Optional[String] @@ -9251,6 +9271,8 @@ class ServiceConfiguration(TypedDict, total=False): PrivateDnsNameConfiguration: Optional[PrivateDnsNameConfiguration] PayerResponsibility: Optional[PayerResponsibility] Tags: Optional[TagList] + SupportedRegions: Optional[SupportedRegionSet] + RemoteAccessEnabled: Optional[Boolean] class CreateVpcEndpointServiceConfigurationResult(TypedDict, total=False): @@ -13626,6 +13648,9 @@ class Snapshot(TypedDict, total=False): StorageTier: Optional[StorageTier] RestoreExpiryTime: Optional[MillisecondDateTime] SseType: Optional[SSEType] + TransferType: Optional[TransferType] + CompletionDurationMinutes: Optional[SnapshotCompletionDurationMinutesResponse] + CompletionTime: Optional[MillisecondDateTime] SnapshotId: Optional[String] VolumeId: Optional[String] State: Optional[SnapshotState] @@ -14785,6 +14810,7 @@ class VpcEndpointConnection(TypedDict, total=False): IpAddressType: Optional[IpAddressType] VpcEndpointConnectionId: Optional[String] Tags: Optional[TagList] + VpcEndpointRegion: Optional[String] VpcEndpointConnectionSet = List[VpcEndpointConnection] @@ -14830,6 +14856,7 @@ class DescribeVpcEndpointServicesRequest(ServiceRequest): Filters: Optional[FilterList] MaxResults: Optional[Integer] NextToken: Optional[String] + ServiceRegions: Optional[ValueStringList] class PrivateDnsDetails(TypedDict, total=False): @@ -14843,6 +14870,7 @@ class ServiceDetail(TypedDict, total=False): ServiceName: Optional[String] ServiceId: Optional[String] ServiceType: Optional[ServiceTypeDetailSet] + ServiceRegion: Optional[String] AvailabilityZones: Optional[ValueStringList] Owner: Optional[String] BaseEndpointDnsNames: Optional[ValueStringList] @@ -17935,6 +17963,8 @@ class ModifyVpcEndpointServiceConfigurationRequest(ServiceRequest): RemoveGatewayLoadBalancerArns: Optional[ValueStringList] AddSupportedIpAddressTypes: Optional[ValueStringList] RemoveSupportedIpAddressTypes: Optional[ValueStringList] + AddSupportedRegions: Optional[ValueStringList] + RemoveSupportedRegions: Optional[ValueStringList] class ModifyVpcEndpointServiceConfigurationResult(TypedDict, total=False): @@ -19822,6 +19852,7 @@ def copy_snapshot( kms_key_id: KmsKeyId = None, presigned_url: CopySnapshotRequestPSU = None, tag_specifications: TagSpecificationList = None, + completion_duration_minutes: SnapshotCompletionDurationMinutesRequest = None, dry_run: Boolean = None, **kwargs, ) -> CopySnapshotResult: @@ -20978,6 +21009,7 @@ def create_vpc_endpoint( private_dns_enabled: Boolean = None, tag_specifications: TagSpecificationList = None, subnet_configurations: SubnetConfigurationsList = None, + service_region: String = None, **kwargs, ) -> CreateVpcEndpointResult: raise NotImplementedError @@ -21006,6 +21038,7 @@ def create_vpc_endpoint_service_configuration( network_load_balancer_arns: ValueStringList = None, gateway_load_balancer_arns: ValueStringList = None, supported_ip_address_types: ValueStringList = None, + supported_regions: ValueStringList = None, client_token: String = None, tag_specifications: TagSpecificationList = None, **kwargs, @@ -23829,6 +23862,7 @@ def describe_vpc_endpoint_services( filters: FilterList = None, max_results: Integer = None, next_token: String = None, + service_regions: ValueStringList = None, **kwargs, ) -> DescribeVpcEndpointServicesResult: raise NotImplementedError @@ -25975,6 +26009,8 @@ def modify_vpc_endpoint_service_configuration( remove_gateway_load_balancer_arns: ValueStringList = None, add_supported_ip_address_types: ValueStringList = None, remove_supported_ip_address_types: ValueStringList = None, + add_supported_regions: ValueStringList = None, + remove_supported_regions: ValueStringList = None, **kwargs, ) -> ModifyVpcEndpointServiceConfigurationResult: raise NotImplementedError diff --git a/localstack-core/localstack/aws/api/s3/__init__.py b/localstack-core/localstack/aws/api/s3/__init__.py index 92e990daf1ce3..5abea18a13fbc 100644 --- a/localstack-core/localstack/aws/api/s3/__init__.py +++ b/localstack-core/localstack/aws/api/s3/__init__.py @@ -1338,6 +1338,7 @@ class CompleteMultipartUploadRequest(ServiceRequest): ChecksumSHA256: Optional[ChecksumSHA256] RequestPayer: Optional[RequestPayer] ExpectedBucketOwner: Optional[AccountId] + IfMatch: Optional[IfMatch] IfNoneMatch: Optional[IfNoneMatch] SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] SSECustomerKey: Optional[SSECustomerKey] @@ -3196,6 +3197,7 @@ class PutObjectRequest(ServiceRequest): ChecksumSHA1: Optional[ChecksumSHA1] ChecksumSHA256: Optional[ChecksumSHA256] Expires: Optional[Expires] + IfMatch: Optional[IfMatch] IfNoneMatch: Optional[IfNoneMatch] GrantFullControl: Optional[GrantFullControl] GrantRead: Optional[GrantRead] @@ -3516,6 +3518,7 @@ def complete_multipart_upload( checksum_sha256: ChecksumSHA256 = None, request_payer: RequestPayer = None, expected_bucket_owner: AccountId = None, + if_match: IfMatch = None, if_none_match: IfNoneMatch = None, sse_customer_algorithm: SSECustomerAlgorithm = None, sse_customer_key: SSECustomerKey = None, @@ -4654,6 +4657,7 @@ def put_object( checksum_sha1: ChecksumSHA1 = None, checksum_sha256: ChecksumSHA256 = None, expires: Expires = None, + if_match: IfMatch = None, if_none_match: IfNoneMatch = None, grant_full_control: GrantFullControl = None, grant_read: GrantRead = None, diff --git a/localstack-core/localstack/services/s3/provider.py b/localstack-core/localstack/services/s3/provider.py index f8a25779ff1c1..46007b83fa871 100644 --- a/localstack-core/localstack/services/s3/provider.py +++ b/localstack-core/localstack/services/s3/provider.py @@ -2358,6 +2358,7 @@ def complete_multipart_upload( checksum_sha256: ChecksumSHA256 = None, request_payer: RequestPayer = None, expected_bucket_owner: AccountId = None, + if_match: IfMatch = None, if_none_match: IfNoneMatch = None, sse_customer_algorithm: SSECustomerAlgorithm = None, sse_customer_key: SSECustomerKey = None, diff --git a/pyproject.toml b/pyproject.toml index 69b8abc37d5b6..6a2b8da3102f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,9 +53,9 @@ Issues = "https://github.com/localstack/localstack/issues" # minimal required to actually run localstack on the host for services natively implemented in python base-runtime = [ # pinned / updated by ASF update action - "boto3==1.35.68", + "boto3==1.35.70", # pinned / updated by ASF update action - "botocore==1.35.68", + "botocore==1.35.70", "awscrt>=0.13.14", "cbor2>=5.2.0", "dnspython>=1.16.0", diff --git a/requirements-base-runtime.txt b/requirements-base-runtime.txt index d9ed46c27701c..7a94c0fedfe50 100644 --- a/requirements-base-runtime.txt +++ b/requirements-base-runtime.txt @@ -11,9 +11,9 @@ attrs==24.2.0 # referencing awscrt==0.23.1 # via localstack-core (pyproject.toml) -boto3==1.35.68 +boto3==1.35.70 # via localstack-core (pyproject.toml) -botocore==1.35.68 +botocore==1.35.70 # via # boto3 # localstack-core (pyproject.toml) diff --git a/requirements-dev.txt b/requirements-dev.txt index 27f505b6fde72..fc646b29b3c03 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -43,17 +43,17 @@ aws-sam-translator==1.94.0 # localstack-core aws-xray-sdk==2.14.0 # via moto-ext -awscli==1.36.9 +awscli==1.36.11 # via localstack-core awscrt==0.23.1 # via localstack-core -boto3==1.35.68 +boto3==1.35.70 # via # amazon-kclpy # aws-sam-translator # localstack-core # moto-ext -botocore==1.35.68 +botocore==1.35.70 # via # aws-xray-sdk # awscli diff --git a/requirements-runtime.txt b/requirements-runtime.txt index 1dab31c0cbbfd..92eba8285189d 100644 --- a/requirements-runtime.txt +++ b/requirements-runtime.txt @@ -29,17 +29,17 @@ aws-sam-translator==1.94.0 # localstack-core (pyproject.toml) aws-xray-sdk==2.14.0 # via moto-ext -awscli==1.36.9 +awscli==1.36.11 # via localstack-core (pyproject.toml) awscrt==0.23.1 # via localstack-core -boto3==1.35.68 +boto3==1.35.70 # via # amazon-kclpy # aws-sam-translator # localstack-core # moto-ext -botocore==1.35.68 +botocore==1.35.70 # via # aws-xray-sdk # awscli diff --git a/requirements-test.txt b/requirements-test.txt index 7a4029a29be60..4c0939bab302a 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -43,17 +43,17 @@ aws-sam-translator==1.94.0 # localstack-core aws-xray-sdk==2.14.0 # via moto-ext -awscli==1.36.9 +awscli==1.36.11 # via localstack-core awscrt==0.23.1 # via localstack-core -boto3==1.35.68 +boto3==1.35.70 # via # amazon-kclpy # aws-sam-translator # localstack-core # moto-ext -botocore==1.35.68 +botocore==1.35.70 # via # aws-xray-sdk # awscli diff --git a/requirements-typehint.txt b/requirements-typehint.txt index c20ecfe99a4b9..d2950bcd3afd1 100644 --- a/requirements-typehint.txt +++ b/requirements-typehint.txt @@ -43,11 +43,11 @@ aws-sam-translator==1.94.0 # localstack-core aws-xray-sdk==2.14.0 # via moto-ext -awscli==1.36.9 +awscli==1.36.11 # via localstack-core awscrt==0.23.1 # via localstack-core -boto3==1.35.68 +boto3==1.35.70 # via # amazon-kclpy # aws-sam-translator @@ -55,7 +55,7 @@ boto3==1.35.68 # moto-ext boto3-stubs==1.35.69 # via localstack-core (pyproject.toml) -botocore==1.35.68 +botocore==1.35.70 # via # aws-xray-sdk # awscli From cf4b1242ca0b3cd5c02d1b7f6e3397f0528c3540 Mon Sep 17 00:00:00 2001 From: MEPalma <64580864+MEPalma@users.noreply.github.com> Date: Wed, 27 Nov 2024 09:27:41 +0100 Subject: [PATCH 16/38] StepFunctions: Improve Activity Name and Arn Validation Logic (#11924) --- .../services/stepfunctions/provider.py | 4 +- .../v2/test_sfn_api_activities.py | 56 +- .../v2/test_sfn_api_activities.snapshot.json | 879 ++++++++++++++++-- .../test_sfn_api_activities.validation.json | 107 ++- 4 files changed, 976 insertions(+), 70 deletions(-) diff --git a/localstack-core/localstack/services/stepfunctions/provider.py b/localstack-core/localstack/services/stepfunctions/provider.py index 0399d32890ac6..690dd68f8b43b 100644 --- a/localstack-core/localstack/services/stepfunctions/provider.py +++ b/localstack-core/localstack/services/stepfunctions/provider.py @@ -175,7 +175,7 @@ def accept_state_visitor(self, visitor: StateVisitor): ) _ACTIVITY_ARN_REGEX: Final[re.Pattern] = re.compile( - rf"{ARN_PARTITION_REGEX}:states:[a-z0-9-]+:[0-9]{{12}}:activity:[a-zA-Z0-9-_]+$" + rf"{ARN_PARTITION_REGEX}:states:[a-z0-9-]+:[0-9]{{12}}:activity:[a-zA-Z0-9-_\.]{{1,80}}$" ) @staticmethod @@ -221,6 +221,8 @@ def _validate_activity_name(name: str) -> None: # - special characters " # % \ ^ | ~ ` $ & , ; : / # - control characters (U+0000-001F, U+007F-009F) # https://docs.aws.amazon.com/step-functions/latest/apireference/API_CreateActivity.html#API_CreateActivity_RequestSyntax + if not (1 <= len(name) <= 80): + raise InvalidName(f"Invalid Name: '{name}'") invalid_chars = set(' <>{}[]?*"#%\\^|~`$&,;:/') control_chars = {chr(i) for i in range(32)} | {chr(i) for i in range(127, 160)} invalid_chars |= control_chars diff --git a/tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py b/tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py index bcfbc4a857f5c..34c31e7c8cc33 100644 --- a/tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py +++ b/tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py @@ -6,16 +6,31 @@ from localstack.utils.strings import short_uid -@markers.snapshot.skip_snapshot_verify(paths=["$..tracingConfiguration"]) +@markers.snapshot.skip_snapshot_verify(paths=["$..encryptionConfiguration"]) class TestSnfApiActivities: @markers.aws.validated + @pytest.mark.parametrize( + "activity_base_name", + [ + "Activity1", + "activity-name_123", + "ACTIVITY_NAME_ABC", + "activity.name", + "activity.name.v2", + "activityName.with.dots", + "activity-name.1", + "activity_123.name", + "a" * 71, # this plus the uuid postfix is a name of length 80 + ], + ) def test_create_describe_delete_activity( self, create_activity, sfn_snapshot, aws_client, + activity_base_name, ): - activity_name = f"TestActivity-{short_uid()}" + activity_name = f"{activity_base_name}-{short_uid()}" create_activity_response = aws_client.stepfunctions.create_activity(name=activity_name) activity_arn = create_activity_response["activityArn"] sfn_snapshot.add_transformer(RegexTransformer(activity_arn, "activity_arn")) @@ -48,13 +63,40 @@ def test_create_describe_delete_activity( sfn_snapshot.match("delete_activity_response_2", delete_activity_response_2) @markers.aws.validated + @pytest.mark.parametrize( + "activity_name", + [ + "activity name", + "activityname", + "activity{name", + "activity}name", + "activity[name", + "activity]name", + "activity?name", + "activity*name", + 'activity"name', + "activity#name", + "activity%name", + "activity\\name", + "activity^name", + "activity|name", + "activity~name", + "activity`name", + "activity$name", + "activity&name", + "activity,name", + "activity;name", + "activity:name", + "activity/name", + chr(0) + "activity", + "activity" + chr(31), + "activity" + chr(127), + ], + ) def test_create_activity_invalid_name( - self, - create_activity, - sfn_snapshot, - aws_client, + self, create_activity, sfn_snapshot, aws_client, activity_name ): - activity_name = "TestActivity InvalidName$" with pytest.raises(ClientError) as e: aws_client.stepfunctions.create_activity(name=activity_name) sfn_snapshot.match("invalid_name", e.value.response) diff --git a/tests/aws/services/stepfunctions/v2/test_sfn_api_activities.snapshot.json b/tests/aws/services/stepfunctions/v2/test_sfn_api_activities.snapshot.json index 99e7deb55ff58..3ea059b17717d 100644 --- a/tests/aws/services/stepfunctions/v2/test_sfn_api_activities.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/test_sfn_api_activities.snapshot.json @@ -1,62 +1,4 @@ { - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity": { - "recorded-date": "03-03-2024, 06:03:28", - "recorded-content": { - "create_activity_response": { - "activityArn": "activity_arn", - "creationDate": "creation-date", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "create_activity_response_duplicate": { - "activityArn": "activity_arn", - "creationDate": "creation-date", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "describe_activity_response": { - "activityArn": "activity_arn", - "creationDate": "creation-date", - "name": "activity_name", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "delete_activity_response": { - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "delete_activity_response_2": { - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - } - } - }, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name": { - "recorded-date": "04-03-2024, 14:18:50", - "recorded-content": { - "invalid_name": { - "Error": { - "Code": "InvalidName", - "Message": "Invalid Name: 'TestActivity InvalidName$'" - }, - "message": "Invalid Name: 'TestActivity InvalidName$'", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 400 - } - } - } - }, "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_describe_deleted_activity": { "recorded-date": "17-03-2024, 10:33:44", "recorded-content": { @@ -134,5 +76,826 @@ } } } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[Activity1]": { + "recorded-date": "25-11-2024, 19:02:40", + "recorded-content": { + "create_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create_activity_response_duplicate": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "encryptionConfiguration": { + "type": "AWS_OWNED_KEY" + }, + "name": "activity_name", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response_2": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity-name_123]": { + "recorded-date": "25-11-2024, 19:02:40", + "recorded-content": { + "create_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create_activity_response_duplicate": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "encryptionConfiguration": { + "type": "AWS_OWNED_KEY" + }, + "name": "activity_name", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response_2": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[ACTIVITY_NAME_ABC]": { + "recorded-date": "25-11-2024, 19:02:41", + "recorded-content": { + "create_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create_activity_response_duplicate": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "encryptionConfiguration": { + "type": "AWS_OWNED_KEY" + }, + "name": "activity_name", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response_2": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity.name]": { + "recorded-date": "25-11-2024, 19:02:42", + "recorded-content": { + "create_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create_activity_response_duplicate": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "encryptionConfiguration": { + "type": "AWS_OWNED_KEY" + }, + "name": "activity_name", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response_2": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity.name.v2]": { + "recorded-date": "25-11-2024, 19:02:42", + "recorded-content": { + "create_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create_activity_response_duplicate": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "encryptionConfiguration": { + "type": "AWS_OWNED_KEY" + }, + "name": "activity_name", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response_2": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activityName.with.dots]": { + "recorded-date": "25-11-2024, 19:02:42", + "recorded-content": { + "create_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create_activity_response_duplicate": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "encryptionConfiguration": { + "type": "AWS_OWNED_KEY" + }, + "name": "activity_name", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response_2": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity-name.1]": { + "recorded-date": "25-11-2024, 19:02:43", + "recorded-content": { + "create_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create_activity_response_duplicate": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "encryptionConfiguration": { + "type": "AWS_OWNED_KEY" + }, + "name": "activity_name", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response_2": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity_123.name]": { + "recorded-date": "25-11-2024, 19:02:43", + "recorded-content": { + "create_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create_activity_response_duplicate": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "encryptionConfiguration": { + "type": "AWS_OWNED_KEY" + }, + "name": "activity_name", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response_2": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]": { + "recorded-date": "25-11-2024, 19:02:44", + "recorded-content": { + "create_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create_activity_response_duplicate": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe_activity_response": { + "activityArn": "activity_arn", + "creationDate": "creation-date", + "encryptionConfiguration": { + "type": "AWS_OWNED_KEY" + }, + "name": "activity_name", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_activity_response_2": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity name]": { + "recorded-date": "25-11-2024, 19:07:31", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity name'" + }, + "message": "Invalid Name: 'activity name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activityname]": { + "recorded-date": "25-11-2024, 19:07:31", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity>name'" + }, + "message": "Invalid Name: 'activity>name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity{name]": { + "recorded-date": "25-11-2024, 19:07:31", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity{name'" + }, + "message": "Invalid Name: 'activity{name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity}name]": { + "recorded-date": "25-11-2024, 19:07:32", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity}name'" + }, + "message": "Invalid Name: 'activity}name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity[name]": { + "recorded-date": "25-11-2024, 19:07:32", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity[name'" + }, + "message": "Invalid Name: 'activity[name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity]name]": { + "recorded-date": "25-11-2024, 19:07:32", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity]name'" + }, + "message": "Invalid Name: 'activity]name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity?name]": { + "recorded-date": "25-11-2024, 19:07:32", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity?name'" + }, + "message": "Invalid Name: 'activity?name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity*name]": { + "recorded-date": "25-11-2024, 19:07:32", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity*name'" + }, + "message": "Invalid Name: 'activity*name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\"name]": { + "recorded-date": "25-11-2024, 19:07:32", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity\"name'" + }, + "message": "Invalid Name: 'activity\"name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity#name]": { + "recorded-date": "25-11-2024, 19:07:32", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity#name'" + }, + "message": "Invalid Name: 'activity#name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity%name]": { + "recorded-date": "25-11-2024, 19:07:32", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity%name'" + }, + "message": "Invalid Name: 'activity%name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\\\\name]": { + "recorded-date": "25-11-2024, 19:07:33", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity\\name'" + }, + "message": "Invalid Name: 'activity\\name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity^name]": { + "recorded-date": "25-11-2024, 19:07:33", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity^name'" + }, + "message": "Invalid Name: 'activity^name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity|name]": { + "recorded-date": "25-11-2024, 19:07:33", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity|name'" + }, + "message": "Invalid Name: 'activity|name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity~name]": { + "recorded-date": "25-11-2024, 19:07:33", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity~name'" + }, + "message": "Invalid Name: 'activity~name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity`name]": { + "recorded-date": "25-11-2024, 19:07:33", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity`name'" + }, + "message": "Invalid Name: 'activity`name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity$name]": { + "recorded-date": "25-11-2024, 19:07:33", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity$name'" + }, + "message": "Invalid Name: 'activity$name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity&name]": { + "recorded-date": "25-11-2024, 19:07:33", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity&name'" + }, + "message": "Invalid Name: 'activity&name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity,name]": { + "recorded-date": "25-11-2024, 19:07:33", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity,name'" + }, + "message": "Invalid Name: 'activity,name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity;name]": { + "recorded-date": "25-11-2024, 19:07:33", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity;name'" + }, + "message": "Invalid Name: 'activity;name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity:name]": { + "recorded-date": "25-11-2024, 19:07:34", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity:name'" + }, + "message": "Invalid Name: 'activity:name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity/name]": { + "recorded-date": "25-11-2024, 19:07:34", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity/name'" + }, + "message": "Invalid Name: 'activity/name'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[\\x00activity]": { + "recorded-date": "25-11-2024, 19:07:34", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: '\u0000activity'" + }, + "message": "Invalid Name: '\u0000activity'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\\x1f]": { + "recorded-date": "25-11-2024, 19:07:34", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity\u001f'" + }, + "message": "Invalid Name: 'activity\u001f'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\\x7f]": { + "recorded-date": "25-11-2024, 19:07:34", + "recorded-content": { + "invalid_name": { + "Error": { + "Code": "InvalidName", + "Message": "Invalid Name: 'activity\u007f'" + }, + "message": "Invalid Name: 'activity\u007f'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } } } diff --git a/tests/aws/services/stepfunctions/v2/test_sfn_api_activities.validation.json b/tests/aws/services/stepfunctions/v2/test_sfn_api_activities.validation.json index 63002fe470f2a..c0e5007ee3626 100644 --- a/tests/aws/services/stepfunctions/v2/test_sfn_api_activities.validation.json +++ b/tests/aws/services/stepfunctions/v2/test_sfn_api_activities.validation.json @@ -1,9 +1,108 @@ { - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name": { - "last_validated_date": "2024-03-04T14:18:50+00:00" + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[\\x00activity]": { + "last_validated_date": "2024-11-25T19:07:34+00:00" }, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity": { - "last_validated_date": "2024-03-03T06:03:28+00:00" + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity name]": { + "last_validated_date": "2024-11-25T19:07:31+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\"name]": { + "last_validated_date": "2024-11-25T19:07:32+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity#name]": { + "last_validated_date": "2024-11-25T19:07:32+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity$name]": { + "last_validated_date": "2024-11-25T19:07:33+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity%name]": { + "last_validated_date": "2024-11-25T19:07:32+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity&name]": { + "last_validated_date": "2024-11-25T19:07:33+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity*name]": { + "last_validated_date": "2024-11-25T19:07:32+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity,name]": { + "last_validated_date": "2024-11-25T19:07:33+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity/name]": { + "last_validated_date": "2024-11-25T19:07:34+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity:name]": { + "last_validated_date": "2024-11-25T19:07:34+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity;name]": { + "last_validated_date": "2024-11-25T19:07:33+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activityname]": { + "last_validated_date": "2024-11-25T19:07:31+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity?name]": { + "last_validated_date": "2024-11-25T19:07:32+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity[name]": { + "last_validated_date": "2024-11-25T19:07:32+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\\\\name]": { + "last_validated_date": "2024-11-25T19:07:33+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\\x1f]": { + "last_validated_date": "2024-11-25T19:07:34+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\\x7f]": { + "last_validated_date": "2024-11-25T19:07:34+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity]name]": { + "last_validated_date": "2024-11-25T19:07:32+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity^name]": { + "last_validated_date": "2024-11-25T19:07:33+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity`name]": { + "last_validated_date": "2024-11-25T19:07:33+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity{name]": { + "last_validated_date": "2024-11-25T19:07:31+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity|name]": { + "last_validated_date": "2024-11-25T19:07:33+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity}name]": { + "last_validated_date": "2024-11-25T19:07:32+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity~name]": { + "last_validated_date": "2024-11-25T19:07:33+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[ACTIVITY_NAME_ABC]": { + "last_validated_date": "2024-11-25T19:02:41+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[Activity1]": { + "last_validated_date": "2024-11-25T19:02:40+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]": { + "last_validated_date": "2024-11-25T19:02:44+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity-name.1]": { + "last_validated_date": "2024-11-25T19:02:43+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity-name_123]": { + "last_validated_date": "2024-11-25T19:02:40+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity.name.v2]": { + "last_validated_date": "2024-11-25T19:02:42+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity.name]": { + "last_validated_date": "2024-11-25T19:02:42+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activityName.with.dots]": { + "last_validated_date": "2024-11-25T19:02:42+00:00" + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity_123.name]": { + "last_validated_date": "2024-11-25T19:02:43+00:00" }, "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_describe_activity_invalid_arn": { "last_validated_date": "2024-03-11T20:38:07+00:00" From 04c02da6a105cf887ef5bfdf7e57ff65e7f30b3e Mon Sep 17 00:00:00 2001 From: Macwan Nevil Date: Wed, 27 Nov 2024 16:07:17 +0530 Subject: [PATCH 17/38] fixed java lib path for macos (#11892) --- localstack-core/localstack/packages/java.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/localstack-core/localstack/packages/java.py b/localstack-core/localstack/packages/java.py index 3c69c7cb880ea..c37792ffc011a 100644 --- a/localstack-core/localstack/packages/java.py +++ b/localstack-core/localstack/packages/java.py @@ -45,7 +45,7 @@ def get_java_lib_path(self) -> str | None: """ if java_home := self.get_java_home(): if is_mac_os(): - return os.path.join(java_home, "Contents", "Home", "lib", "jli", "libjli.dylib") + return os.path.join(java_home, "lib", "jli", "libjli.dylib") return os.path.join(java_home, "lib", "server", "libjvm.so") def get_java_env_vars(self, path: str = None, ld_library_path: str = None) -> dict[str, str]: From b28bad3bfd2de9cd320b3da55cd168b3b7c94988 Mon Sep 17 00:00:00 2001 From: Ben Simon Hartung <42031100+bentsku@users.noreply.github.com> Date: Wed, 27 Nov 2024 13:11:18 +0100 Subject: [PATCH 18/38] implement S3 conditional write `IfMatch` (#11941) --- .../localstack/services/s3/provider.py | 62 ++- tests/aws/services/s3/test_s3_api.py | 311 +++++++++++ .../aws/services/s3/test_s3_api.snapshot.json | 506 ++++++++++++++++++ .../services/s3/test_s3_api.validation.json | 24 + 4 files changed, 899 insertions(+), 4 deletions(-) diff --git a/localstack-core/localstack/services/s3/provider.py b/localstack-core/localstack/services/s3/provider.py index 46007b83fa871..5e24508bace46 100644 --- a/localstack-core/localstack/services/s3/provider.py +++ b/localstack-core/localstack/services/s3/provider.py @@ -660,11 +660,20 @@ def put_object( validate_object_key(key) - if (if_none_match := request.get("IfNoneMatch")) and if_none_match != "*": + if_match = request.get("IfMatch") + if (if_none_match := request.get("IfNoneMatch")) and if_match: raise NotImplementedException( "A header you provided implies functionality that is not implemented", - Header="If-None-Match", - additionalMessage="We don't accept the provided value of If-None-Match header for this API", + Header="If-Match,If-None-Match", + additionalMessage="Multiple conditional request headers present in the request", + ) + + elif (if_none_match and if_none_match != "*") or (if_match and if_match == "*"): + header_name = "If-None-Match" if if_none_match else "If-Match" + raise NotImplementedException( + "A header you provided implies functionality that is not implemented", + Header=header_name, + additionalMessage=f"We don't accept the provided value of {header_name} header for this API", ) system_metadata = get_system_metadata_from_request(request) @@ -758,6 +767,9 @@ def put_object( Condition="If-None-Match", ) + elif if_match: + verify_object_equality_precondition_write(s3_bucket, key, if_match) + s3_stored_object.write(body) if ( @@ -2377,7 +2389,14 @@ def complete_multipart_upload( UploadId=upload_id, ) - if if_none_match: + if if_none_match and if_match: + raise NotImplementedException( + "A header you provided implies functionality that is not implemented", + Header="If-Match,If-None-Match", + additionalMessage="Multiple conditional request headers present in the request", + ) + + elif if_none_match: if if_none_match != "*": raise NotImplementedException( "A header you provided implies functionality that is not implemented", @@ -2396,6 +2415,17 @@ def complete_multipart_upload( Key=key, ) + elif if_match: + if if_match == "*": + raise NotImplementedException( + "A header you provided implies functionality that is not implemented", + Header="If-None-Match", + additionalMessage="We don't accept the provided value of If-None-Match header for this API", + ) + verify_object_equality_precondition_write( + s3_bucket, key, if_match, initiated=s3_multipart.initiated + ) + parts = multipart_upload.get("Parts", []) if not parts: raise InvalidRequest("You must specify at least one part") @@ -4395,3 +4425,27 @@ def get_access_control_policy_for_new_resource_request( def object_exists_for_precondition_write(s3_bucket: S3Bucket, key: ObjectKey) -> bool: return (existing := s3_bucket.objects.get(key)) and not isinstance(existing, S3DeleteMarker) + + +def verify_object_equality_precondition_write( + s3_bucket: S3Bucket, + key: ObjectKey, + etag: str, + initiated: datetime.datetime | None = None, +) -> None: + existing = s3_bucket.objects.get(key) + if not existing or isinstance(existing, S3DeleteMarker): + raise NoSuchKey("The specified key does not exist.", Key=key) + + if not existing.etag == etag.strip('"'): + raise PreconditionFailed( + "At least one of the pre-conditions you specified did not hold", + Condition="If-Match", + ) + + if initiated and initiated < existing.last_modified: + raise ConditionalRequestConflict( + "The conditional request cannot succeed due to a conflicting operation against this resource.", + Condition="If-Match", + Key=key, + ) diff --git a/tests/aws/services/s3/test_s3_api.py b/tests/aws/services/s3/test_s3_api.py index 54e12ede32aad..d30aec4d8ba6e 100644 --- a/tests/aws/services/s3/test_s3_api.py +++ b/tests/aws/services/s3/test_s3_api.py @@ -1719,6 +1719,10 @@ def test_bucket_acceleration_configuration_exc( class TestS3ObjectWritePrecondition: + """ + https://docs.aws.amazon.com/AmazonS3/latest/userguide/conditional-writes.html + """ + @pytest.fixture(autouse=True) def add_snapshot_transformers(self, snapshot): snapshot.add_transformers_list( @@ -1869,3 +1873,310 @@ def test_put_object_if_none_match_versioned_bucket(self, s3_bucket, aws_client, list_object_versions = aws_client.s3.list_object_versions(Bucket=s3_bucket) snapshot.match("list-object-versions", list_object_versions) + + @markers.aws.validated + def test_put_object_if_match(self, s3_bucket, aws_client, snapshot): + key = "test-precondition" + put_obj = aws_client.s3.put_object(Bucket=s3_bucket, Key=key, Body="test") + snapshot.match("put-obj", put_obj) + etag = put_obj["ETag"] + + with pytest.raises(ClientError) as e: + # empty object is provided + aws_client.s3.put_object( + Bucket=s3_bucket, Key=key, IfMatch="d41d8cd98f00b204e9800998ecf8427e" + ) + snapshot.match("put-obj-if-match-wrong-etag", e.value.response) + + put_obj_overwrite = aws_client.s3.put_object(Bucket=s3_bucket, Key=key, IfMatch=etag) + snapshot.match("put-obj-overwrite", put_obj_overwrite) + + del_obj = aws_client.s3.delete_object(Bucket=s3_bucket, Key=key) + snapshot.match("del-obj", del_obj) + + with pytest.raises(ClientError) as e: + aws_client.s3.put_object(Bucket=s3_bucket, Key=key, IfMatch=etag) + snapshot.match("put-obj-if-match-key-not-exists", e.value.response) + + put_obj_after_del = aws_client.s3.put_object(Bucket=s3_bucket, Key=key) + snapshot.match("put-obj-after-del", put_obj_after_del) + + @markers.aws.validated + def test_put_object_if_match_validation(self, s3_bucket, aws_client, snapshot): + key = "test-precondition-validation" + + with pytest.raises(ClientError) as e: + aws_client.s3.put_object(Bucket=s3_bucket, Key=key, IfMatch="*") + snapshot.match("put-obj-if-match-star-value", e.value.response) + + with pytest.raises(ClientError) as e: + aws_client.s3.put_object(Bucket=s3_bucket, Key=key, IfMatch="abcdef") + snapshot.match("put-obj-if-match-bad-value", e.value.response) + + with pytest.raises(ClientError) as e: + aws_client.s3.put_object(Bucket=s3_bucket, Key=key, IfMatch="bad-char_/") + snapshot.match("put-obj-if-match-bad-value-2", e.value.response) + + @markers.aws.validated + def test_multipart_if_match_with_put(self, s3_bucket, aws_client, snapshot): + key = "test-precondition" + put_obj = aws_client.s3.put_object(Bucket=s3_bucket, Key=key, Body="test") + snapshot.match("put-obj", put_obj) + put_obj_etag_1 = put_obj["ETag"] + + create_multipart = aws_client.s3.create_multipart_upload(Bucket=s3_bucket, Key=key) + snapshot.match("create-multipart", create_multipart) + upload_id = create_multipart["UploadId"] + + upload_part = aws_client.s3.upload_part( + Bucket=s3_bucket, Key=key, UploadId=upload_id, Body="test", PartNumber=1 + ) + parts = [{"ETag": upload_part["ETag"], "PartNumber": 1}] + + put_obj_2 = aws_client.s3.put_object(Bucket=s3_bucket, Key=key, Body="test2") + snapshot.match("put-obj-during", put_obj_2) + put_obj_etag_2 = put_obj_2["ETag"] + + with pytest.raises(ClientError) as e: + aws_client.s3.complete_multipart_upload( + Bucket=s3_bucket, + Key=key, + MultipartUpload={"Parts": parts}, + UploadId=upload_id, + IfMatch=put_obj_etag_1, + ) + snapshot.match("complete-multipart-if-match-put-before", e.value.response) + + # the previous PutObject request was done between the CreateMultipartUpload and completion, so it takes + # precedence + # you need to restart the whole multipart for it to work + with pytest.raises(ClientError) as e: + aws_client.s3.complete_multipart_upload( + Bucket=s3_bucket, + Key=key, + MultipartUpload={"Parts": parts}, + UploadId=upload_id, + IfMatch=put_obj_etag_2, + ) + snapshot.match("complete-multipart-if-match-put-during", e.value.response) + + create_multipart = aws_client.s3.create_multipart_upload(Bucket=s3_bucket, Key=key) + snapshot.match("create-multipart-again", create_multipart) + upload_id = create_multipart["UploadId"] + + upload_part = aws_client.s3.upload_part( + Bucket=s3_bucket, Key=key, UploadId=upload_id, Body="test", PartNumber=1 + ) + parts = [{"ETag": upload_part["ETag"], "PartNumber": 1}] + + complete_multipart = aws_client.s3.complete_multipart_upload( + Bucket=s3_bucket, + Key=key, + MultipartUpload={"Parts": parts}, + UploadId=upload_id, + IfMatch=put_obj_etag_2, + ) + snapshot.match("complete-multipart-if-match-put-before-restart", complete_multipart) + + @markers.aws.validated + def test_multipart_if_match_with_put_identical(self, s3_bucket, aws_client, snapshot): + key = "test-precondition" + put_obj = aws_client.s3.put_object(Bucket=s3_bucket, Key=key, Body="test") + snapshot.match("put-obj", put_obj) + put_obj_etag_1 = put_obj["ETag"] + + create_multipart = aws_client.s3.create_multipart_upload(Bucket=s3_bucket, Key=key) + snapshot.match("create-multipart", create_multipart) + upload_id = create_multipart["UploadId"] + + upload_part = aws_client.s3.upload_part( + Bucket=s3_bucket, Key=key, UploadId=upload_id, Body="test", PartNumber=1 + ) + parts = [{"ETag": upload_part["ETag"], "PartNumber": 1}] + + put_obj_2 = aws_client.s3.put_object(Bucket=s3_bucket, Key=key, Body="test") + snapshot.match("put-obj-during", put_obj_2) + # same ETag as first put + put_obj_etag_2 = put_obj_2["ETag"] + assert put_obj_etag_1 == put_obj_etag_2 + + # it seems that even if we overwrite the object with the same content, S3 will still reject the request if a + # write operation was done between creation and completion of the multipart upload, like the `Delete` + # counterpart of `IfNoneMatch` + + with pytest.raises(ClientError) as e: + aws_client.s3.complete_multipart_upload( + Bucket=s3_bucket, + Key=key, + MultipartUpload={"Parts": parts}, + UploadId=upload_id, + IfMatch=put_obj_etag_2, + ) + snapshot.match("complete-multipart-if-match-put-during", e.value.response) + # the previous PutObject request was done between the CreateMultipartUpload and completion, so it takes + # precedence + # you need to restart the whole multipart for it to work + + create_multipart = aws_client.s3.create_multipart_upload(Bucket=s3_bucket, Key=key) + snapshot.match("create-multipart-again", create_multipart) + upload_id = create_multipart["UploadId"] + + upload_part = aws_client.s3.upload_part( + Bucket=s3_bucket, Key=key, UploadId=upload_id, Body="test", PartNumber=1 + ) + parts = [{"ETag": upload_part["ETag"], "PartNumber": 1}] + + complete_multipart = aws_client.s3.complete_multipart_upload( + Bucket=s3_bucket, + Key=key, + MultipartUpload={"Parts": parts}, + UploadId=upload_id, + IfMatch=put_obj_etag_2, + ) + snapshot.match("complete-multipart-if-match-put-before-restart", complete_multipart) + + @markers.aws.validated + def test_multipart_if_match_with_delete(self, s3_bucket, aws_client, snapshot): + key = "test-precondition" + put_obj = aws_client.s3.put_object(Bucket=s3_bucket, Key=key, Body="test") + snapshot.match("put-obj", put_obj) + obj_etag = put_obj["ETag"] + + create_multipart = aws_client.s3.create_multipart_upload(Bucket=s3_bucket, Key=key) + snapshot.match("create-multipart", create_multipart) + upload_id = create_multipart["UploadId"] + + upload_part = aws_client.s3.upload_part( + Bucket=s3_bucket, Key=key, UploadId=upload_id, Body="test", PartNumber=1 + ) + parts = [{"ETag": upload_part["ETag"], "PartNumber": 1}] + + del_obj = aws_client.s3.delete_object(Bucket=s3_bucket, Key=key) + snapshot.match("del-obj", del_obj) + + with pytest.raises(ClientError) as e: + aws_client.s3.complete_multipart_upload( + Bucket=s3_bucket, + Key=key, + MultipartUpload={"Parts": parts}, + UploadId=upload_id, + IfMatch=obj_etag, + ) + snapshot.match("complete-multipart-after-del", e.value.response) + + put_obj_2 = aws_client.s3.put_object(Bucket=s3_bucket, Key=key, Body="test") + snapshot.match("put-obj-2", put_obj_2) + obj_etag_2 = put_obj_2["ETag"] + + with pytest.raises(ClientError) as e: + # even if we recreated the object, it still fails as it was done after the start of the upload + aws_client.s3.complete_multipart_upload( + Bucket=s3_bucket, + Key=key, + MultipartUpload={"Parts": parts}, + UploadId=upload_id, + IfMatch=obj_etag_2, + ) + snapshot.match("complete-multipart-if-match-after-put", e.value.response) + + @markers.aws.validated + def test_put_object_if_match_versioned_bucket(self, s3_bucket, aws_client, snapshot): + aws_client.s3.put_bucket_versioning( + Bucket=s3_bucket, VersioningConfiguration={"Status": "Enabled"} + ) + key = "test-precondition" + put_obj = aws_client.s3.put_object(Bucket=s3_bucket, Key=key, Body="test") + snapshot.match("put-obj", put_obj) + put_obj_etag_1 = put_obj["ETag"] + + with pytest.raises(ClientError) as e: + aws_client.s3.put_object(Bucket=s3_bucket, Key=key, IfMatch="abcdef") + snapshot.match("put-obj-if-none-match-bad-value", e.value.response) + + del_obj = aws_client.s3.delete_object(Bucket=s3_bucket, Key=key) + snapshot.match("del-obj", del_obj) + + # if the last object is a delete marker, then we can't use IfMatch + with pytest.raises(ClientError) as e: + aws_client.s3.put_object(Bucket=s3_bucket, Key=key, IfMatch=put_obj_etag_1) + snapshot.match("put-obj-after-del-exc", e.value.response) + + put_obj_2 = aws_client.s3.put_object(Bucket=s3_bucket, Key=key, Body="test-after-del") + snapshot.match("put-obj-after-del", put_obj_2) + put_obj_etag_2 = put_obj_2["ETag"] + + put_obj_3 = aws_client.s3.put_object( + Bucket=s3_bucket, Key=key, Body="test-if-match", IfMatch=put_obj_etag_2 + ) + snapshot.match("put-obj-if-match", put_obj_3) + + list_object_versions = aws_client.s3.list_object_versions(Bucket=s3_bucket) + snapshot.match("list-object-versions", list_object_versions) + + @markers.aws.validated + def test_put_object_if_match_and_if_none_match_validation( + self, s3_bucket, aws_client, snapshot + ): + key = "test-precondition-validation" + + with pytest.raises(ClientError) as e: + aws_client.s3.put_object(Bucket=s3_bucket, Key=key, IfNoneMatch="*", IfMatch="abcdef") + snapshot.match("put-obj-both-precondition", e.value.response) + + @markers.aws.validated + def test_multipart_if_match_etag(self, s3_bucket, aws_client, snapshot): + key = "test-precondition" + put_obj = aws_client.s3.put_object(Bucket=s3_bucket, Key=key, Body="test") + snapshot.match("put-obj", put_obj) + put_obj_etag_1 = put_obj["ETag"] + + create_multipart = aws_client.s3.create_multipart_upload(Bucket=s3_bucket, Key=key) + snapshot.match("create-multipart", create_multipart) + upload_id = create_multipart["UploadId"] + + upload_part = aws_client.s3.upload_part( + Bucket=s3_bucket, Key=key, UploadId=upload_id, Body="test", PartNumber=1 + ) + parts = [{"ETag": upload_part["ETag"], "PartNumber": 1}] + + complete_multipart_1 = aws_client.s3.complete_multipart_upload( + Bucket=s3_bucket, + Key=key, + MultipartUpload={"Parts": parts}, + UploadId=upload_id, + IfMatch=put_obj_etag_1, + ) + snapshot.match("complete-multipart-if-match", complete_multipart_1) + + multipart_etag = complete_multipart_1["ETag"] + # those are different, because multipart etag contains the amount of parts and is the hash of the hashes of the + # part + assert put_obj_etag_1 != multipart_etag + + create_multipart = aws_client.s3.create_multipart_upload(Bucket=s3_bucket, Key=key) + snapshot.match("create-multipart-overwrite", create_multipart) + upload_id = create_multipart["UploadId"] + + upload_part = aws_client.s3.upload_part( + Bucket=s3_bucket, Key=key, UploadId=upload_id, Body="test", PartNumber=1 + ) + parts = [{"ETag": upload_part["ETag"], "PartNumber": 1}] + + with pytest.raises(ClientError) as e: + aws_client.s3.complete_multipart_upload( + Bucket=s3_bucket, + Key=key, + MultipartUpload={"Parts": parts}, + UploadId=upload_id, + IfMatch=put_obj_etag_1, + ) + snapshot.match("complete-multipart-if-match-true-etag", e.value.response) + + complete_multipart_1 = aws_client.s3.complete_multipart_upload( + Bucket=s3_bucket, + Key=key, + MultipartUpload={"Parts": parts}, + UploadId=upload_id, + IfMatch=multipart_etag, + ) + snapshot.match("complete-multipart-if-match-overwrite-multipart", complete_multipart_1) diff --git a/tests/aws/services/s3/test_s3_api.snapshot.json b/tests/aws/services/s3/test_s3_api.snapshot.json index f46efc33e6944..9f854c113731c 100644 --- a/tests/aws/services/s3/test_s3_api.snapshot.json +++ b/tests/aws/services/s3/test_s3_api.snapshot.json @@ -3653,5 +3653,511 @@ } } } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match": { + "recorded-date": "26-11-2024, 16:57:18", + "recorded-content": { + "put-obj": { + "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "put-obj-if-match-wrong-etag": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "If-Match", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + }, + "put-obj-overwrite": { + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "del-obj": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 204 + } + }, + "put-obj-if-match-key-not-exists": { + "Error": { + "Code": "NoSuchKey", + "Key": "test-precondition", + "Message": "The specified key does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "put-obj-after-del": { + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_validation": { + "recorded-date": "26-11-2024, 20:38:49", + "recorded-content": { + "put-obj-if-match-star-value": { + "Error": { + "Code": "NotImplemented", + "Header": "If-Match", + "Message": "A header you provided implies functionality that is not implemented", + "additionalMessage": "We don't accept the provided value of If-Match header for this API" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 501 + } + }, + "put-obj-if-match-bad-value": { + "Error": { + "Code": "NoSuchKey", + "Key": "test-precondition-validation", + "Message": "The specified key does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "put-obj-if-match-bad-value-2": { + "Error": { + "Code": "NoSuchKey", + "Key": "test-precondition-validation", + "Message": "The specified key does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_put": { + "recorded-date": "26-11-2024, 20:44:46", + "recorded-content": { + "put-obj": { + "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create-multipart": { + "Bucket": "", + "Key": "test-precondition", + "ServerSideEncryption": "AES256", + "UploadId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "put-obj-during": { + "ETag": "\"ad0234829205b9033196ba818f7a872b\"", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "complete-multipart-if-match-put-before": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "If-Match", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + }, + "complete-multipart-if-match-put-during": { + "Error": { + "Code": "ConditionalRequestConflict", + "Condition": "If-Match", + "Key": "test-precondition", + "Message": "The conditional request cannot succeed due to a conflicting operation against this resource." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 409 + } + }, + "create-multipart-again": { + "Bucket": "", + "Key": "test-precondition", + "ServerSideEncryption": "AES256", + "UploadId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "complete-multipart-if-match-put-before-restart": { + "Bucket": "", + "ETag": "\"60cd54a928cbbcbb6e7b5595bab46a9e-1\"", + "Key": "test-precondition", + "Location": "", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_put_identical": { + "recorded-date": "26-11-2024, 23:46:03", + "recorded-content": { + "put-obj": { + "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create-multipart": { + "Bucket": "", + "Key": "test-precondition", + "ServerSideEncryption": "AES256", + "UploadId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "put-obj-during": { + "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "complete-multipart-if-match-put-during": { + "Error": { + "Code": "ConditionalRequestConflict", + "Condition": "If-Match", + "Key": "test-precondition", + "Message": "The conditional request cannot succeed due to a conflicting operation against this resource." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 409 + } + }, + "create-multipart-again": { + "Bucket": "", + "Key": "test-precondition", + "ServerSideEncryption": "AES256", + "UploadId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "complete-multipart-if-match-put-before-restart": { + "Bucket": "", + "ETag": "\"60cd54a928cbbcbb6e7b5595bab46a9e-1\"", + "Key": "test-precondition", + "Location": "", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_delete": { + "recorded-date": "26-11-2024, 23:47:59", + "recorded-content": { + "put-obj": { + "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create-multipart": { + "Bucket": "", + "Key": "test-precondition", + "ServerSideEncryption": "AES256", + "UploadId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "del-obj": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 204 + } + }, + "complete-multipart-after-del": { + "Error": { + "Code": "NoSuchKey", + "Key": "test-precondition", + "Message": "The specified key does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "put-obj-2": { + "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "complete-multipart-if-match-after-put": { + "Error": { + "Code": "ConditionalRequestConflict", + "Condition": "If-Match", + "Key": "test-precondition", + "Message": "The conditional request cannot succeed due to a conflicting operation against this resource." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 409 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_versioned_bucket": { + "recorded-date": "26-11-2024, 23:49:59", + "recorded-content": { + "put-obj": { + "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", + "ServerSideEncryption": "AES256", + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "put-obj-if-none-match-bad-value": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "If-Match", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + }, + "del-obj": { + "DeleteMarker": true, + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 204 + } + }, + "put-obj-after-del-exc": { + "Error": { + "Code": "NoSuchKey", + "Key": "test-precondition", + "Message": "The specified key does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "put-obj-after-del": { + "ETag": "\"b022e6afbcd118faed117e3c2b6e7b19\"", + "ServerSideEncryption": "AES256", + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "put-obj-if-match": { + "ETag": "\"98e41c14fd4ec56bafc444346ecb74b7\"", + "ServerSideEncryption": "AES256", + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-object-versions": { + "DeleteMarkers": [ + { + "IsLatest": false, + "Key": "test-precondition", + "LastModified": "datetime", + "Owner": { + "DisplayName": "", + "ID": "" + }, + "VersionId": "" + } + ], + "EncodingType": "url", + "IsTruncated": false, + "KeyMarker": "", + "MaxKeys": 1000, + "Name": "", + "Prefix": "", + "VersionIdMarker": "", + "Versions": [ + { + "ETag": "\"98e41c14fd4ec56bafc444346ecb74b7\"", + "IsLatest": true, + "Key": "test-precondition", + "LastModified": "datetime", + "Owner": { + "DisplayName": "", + "ID": "" + }, + "Size": 13, + "StorageClass": "STANDARD", + "VersionId": "" + }, + { + "ETag": "\"b022e6afbcd118faed117e3c2b6e7b19\"", + "IsLatest": false, + "Key": "test-precondition", + "LastModified": "datetime", + "Owner": { + "DisplayName": "", + "ID": "" + }, + "Size": 14, + "StorageClass": "STANDARD", + "VersionId": "" + }, + { + "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", + "IsLatest": false, + "Key": "test-precondition", + "LastModified": "datetime", + "Owner": { + "DisplayName": "", + "ID": "" + }, + "Size": 4, + "StorageClass": "STANDARD", + "VersionId": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_and_if_none_match_validation": { + "recorded-date": "26-11-2024, 23:54:00", + "recorded-content": { + "put-obj-both-precondition": { + "Error": { + "Code": "NotImplemented", + "Header": "If-Match,If-None-Match", + "Message": "A header you provided implies functionality that is not implemented", + "additionalMessage": "Multiple conditional request headers present in the request" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 501 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_etag": { + "recorded-date": "27-11-2024, 10:35:20", + "recorded-content": { + "put-obj": { + "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create-multipart": { + "Bucket": "", + "Key": "test-precondition", + "ServerSideEncryption": "AES256", + "UploadId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "complete-multipart-if-match": { + "Bucket": "", + "ETag": "\"60cd54a928cbbcbb6e7b5595bab46a9e-1\"", + "Key": "test-precondition", + "Location": "", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create-multipart-overwrite": { + "Bucket": "", + "Key": "test-precondition", + "ServerSideEncryption": "AES256", + "UploadId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "complete-multipart-if-match-true-etag": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "If-Match", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + }, + "complete-multipart-if-match-overwrite-multipart": { + "Bucket": "", + "ETag": "\"60cd54a928cbbcbb6e7b5595bab46a9e-1\"", + "Key": "test-precondition", + "Location": "", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/s3/test_s3_api.validation.json b/tests/aws/services/s3/test_s3_api.validation.json index 065b5a046f397..bd31ae704dba0 100644 --- a/tests/aws/services/s3/test_s3_api.validation.json +++ b/tests/aws/services/s3/test_s3_api.validation.json @@ -119,12 +119,36 @@ "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_put_object_lock_configuration_on_existing_bucket": { "last_validated_date": "2024-01-15T03:13:25+00:00" }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_etag": { + "last_validated_date": "2024-11-27T10:35:19+00:00" + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_delete": { + "last_validated_date": "2024-11-26T23:47:58+00:00" + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_put": { + "last_validated_date": "2024-11-26T20:44:45+00:00" + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_put_identical": { + "last_validated_date": "2024-11-26T23:46:02+00:00" + }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_none_match_with_delete": { "last_validated_date": "2024-08-21T22:26:26+00:00" }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_none_match_with_put": { "last_validated_date": "2024-08-21T22:26:28+00:00" }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match": { + "last_validated_date": "2024-11-26T16:57:17+00:00" + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_and_if_none_match_validation": { + "last_validated_date": "2024-11-26T23:54:00+00:00" + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_validation": { + "last_validated_date": "2024-11-26T20:38:49+00:00" + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_versioned_bucket": { + "last_validated_date": "2024-11-26T23:49:57+00:00" + }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_none_match": { "last_validated_date": "2024-08-21T22:26:21+00:00" }, From 090230b40d3a7f00c7f50fce813f6f8dd36b687e Mon Sep 17 00:00:00 2001 From: Ben Simon Hartung <42031100+bentsku@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:28:28 +0100 Subject: [PATCH 19/38] fix flaky SES test (#11944) --- tests/aws/services/ses/test_ses.py | 3 +++ tests/aws/services/ses/test_ses.snapshot.json | 4 ++-- tests/aws/services/ses/test_ses.validation.json | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/aws/services/ses/test_ses.py b/tests/aws/services/ses/test_ses.py index b9ba8fe976b8e..0631d8e94ff15 100644 --- a/tests/aws/services/ses/test_ses.py +++ b/tests/aws/services/ses/test_ses.py @@ -260,6 +260,9 @@ def test_sent_message_counter( self, create_template, aws_client, snapshot, setup_email_addresses ): # Ensure all email send operations correctly update the `sent` email counter + snapshot.add_transformer( + snapshot.transform.key_value("SentLast24Hours", reference_replacement=False), + ) def _assert_sent_quota(expected_counter: int) -> dict: _send_quota = aws_client.ses.get_send_quota() diff --git a/tests/aws/services/ses/test_ses.snapshot.json b/tests/aws/services/ses/test_ses.snapshot.json index 8768b0f212481..73336d13e1921 100644 --- a/tests/aws/services/ses/test_ses.snapshot.json +++ b/tests/aws/services/ses/test_ses.snapshot.json @@ -903,12 +903,12 @@ } }, "tests/aws/services/ses/test_ses.py::TestSES::test_sent_message_counter": { - "recorded-date": "25-08-2023, 23:40:26", + "recorded-date": "27-11-2024, 13:03:32", "recorded-content": { "get-quota-0": { "Max24HourSend": 200.0, "MaxSendRate": 1.0, - "SentLast24Hours": 0.0, + "SentLast24Hours": "sent-last24-hours", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 diff --git a/tests/aws/services/ses/test_ses.validation.json b/tests/aws/services/ses/test_ses.validation.json index d5146a78b1157..2a9af7ef3a441 100644 --- a/tests/aws/services/ses/test_ses.validation.json +++ b/tests/aws/services/ses/test_ses.validation.json @@ -51,7 +51,7 @@ "last_validated_date": "2023-08-25T22:02:43+00:00" }, "tests/aws/services/ses/test_ses.py::TestSES::test_sent_message_counter": { - "last_validated_date": "2023-08-25T21:40:26+00:00" + "last_validated_date": "2024-11-27T13:03:32+00:00" }, "tests/aws/services/ses/test_ses.py::TestSES::test_ses_sns_topic_integration_send_email": { "last_validated_date": "2023-08-25T21:53:37+00:00" From 1ff7a48f86b0f73eaaa0593d1201cb6110ea02a1 Mon Sep 17 00:00:00 2001 From: Giovanni Grano Date: Wed, 27 Nov 2024 10:58:06 -0500 Subject: [PATCH 20/38] Extend patch decorator to add methods to class types (#11932) --- localstack-core/localstack/utils/patch.py | 37 ++++++++++++++++++++--- tests/unit/utils/test_patch.py | 26 ++++++++++++++++ 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/localstack-core/localstack/utils/patch.py b/localstack-core/localstack/utils/patch.py index db005d9a5d457..2fa54e3cf2a39 100644 --- a/localstack-core/localstack/utils/patch.py +++ b/localstack-core/localstack/utils/patch.py @@ -1,7 +1,7 @@ import functools import inspect import types -from typing import Any, Callable, List +from typing import Any, Callable, List, Type def get_defining_object(method): @@ -89,17 +89,25 @@ def __init__(self, obj: Any, name: str, new: Any) -> None: super().__init__() self.obj = obj self.name = name - self.old = getattr(self.obj, name) + try: + self.old = getattr(self.obj, name) + except AttributeError: + self.old = None self.new = new self.is_applied = False def apply(self): + if self.old and self.name == "__getattr__": + raise Exception("You can't patch class types implementing __getattr__") + if not self.old and self.name != "__getattr__": + raise AttributeError(f"`{self.obj.__name__}` object has no attribute `{self.name}`") setattr(self.obj, self.name, self.new) self.is_applied = True Patch.applied_patches.append(self) def undo(self): - setattr(self.obj, self.name, self.old) + # If we added a method to a class type, we don't have a self.old. We just delete __getattr__ + setattr(self.obj, self.name, self.old) if self.old else delattr(self.obj, self.name) self.is_applied = False Patch.applied_patches.remove(self) @@ -111,6 +119,16 @@ def __exit__(self, exc_type, exc_val, exc_tb): self.undo() return self + @staticmethod + def extend_class(target: Type, fn: Callable): + def _getattr(obj, name): + if name != fn.__name__: + raise AttributeError(f"`{target.__name__}` object has no attribute `{name}`") + + return functools.partial(fn, obj) + + return Patch(target, "__getattr__", _getattr) + @staticmethod def function(target: Callable, fn: Callable, pass_target: bool = True): obj = get_defining_object(target) @@ -210,6 +228,13 @@ def my_patch(fn, self, *args): def my_patch(self, *args): ... + This decorator can also patch a class type with a new method. + + For example: + @patch(target=MyEchoer) + def new_echo(self, *args): + ... + :param target: the function or method to patch :param pass_target: whether to pass the target to the patching function as first parameter :returns: the same function, but with a patch created @@ -217,7 +242,11 @@ def my_patch(self, *args): @functools.wraps(target) def wrapper(fn): - fn.patch = Patch.function(target, fn, pass_target=pass_target) + fn.patch = ( + Patch.extend_class(target, fn) + if inspect.isclass(target) + else Patch.function(target, fn, pass_target=pass_target) + ) fn.patch.apply() return fn diff --git a/tests/unit/utils/test_patch.py b/tests/unit/utils/test_patch.py index 20b19174ca144..3b6d2685e4a17 100644 --- a/tests/unit/utils/test_patch.py +++ b/tests/unit/utils/test_patch.py @@ -202,3 +202,29 @@ def monkey(self, *args): value = "Patch(function(tests.unit.utils.test_patch:MyEchoer.do_echo) -> function(tests.unit.utils.test_patch:test_to_string..monkey), applied=True)" assert value in applied assert str(monkey.patch) == value + monkey.patch.undo() + + +def test_patch_class_type(): + @patch(MyEchoer) + def new_echo(self, *args): + return args[1] + + echoer = MyEchoer() + assert echoer.new_echo(1, 2, 3) == 2 + new_echo.patch.undo() + with pytest.raises(AttributeError): + echoer.new_echo("Hello world!") + + @patch(MyEchoer) + def do_echo(self, arg): + return arg + + echoer = MyEchoer() + assert echoer.do_echo(1) == "do_echo: 1", "existing method is overridden" + + with pytest.raises(AttributeError): + + @patch(MyEchoer.new_echo) + def new_echo(self, *args): + pass From 0331d0e4fa60eb65cfb95b33a7e78a7c5dc45c8e Mon Sep 17 00:00:00 2001 From: Joel Scheuner Date: Wed, 27 Nov 2024 17:59:04 +0100 Subject: [PATCH 21/38] Add analytics for event rule engine (#11928) --- localstack-core/localstack/runtime/analytics.py | 1 + localstack-core/localstack/services/events/plugins.py | 8 ++++++++ tests/aws/services/events/test_events_patterns.py | 4 ++-- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 localstack-core/localstack/services/events/plugins.py diff --git a/localstack-core/localstack/runtime/analytics.py b/localstack-core/localstack/runtime/analytics.py index 226710c1dcc78..4ef2c4ba59ae0 100644 --- a/localstack-core/localstack/runtime/analytics.py +++ b/localstack-core/localstack/runtime/analytics.py @@ -31,6 +31,7 @@ "ES_CUSTOM_BACKEND", # deprecated in 0.14.0, removed in 3.0.0 "ES_MULTI_CLUSTER", # deprecated in 0.14.0, removed in 3.0.0 "ES_ENDPOINT_STRATEGY", # deprecated in 0.14.0, removed in 3.0.0 + "EVENT_RULE_ENGINE", "IAM_SOFT_MODE", "KINESIS_PROVIDER", # Not functional; deprecated in 2.0.0, removed in 3.0.0 "KINESIS_ERROR_PROBABILITY", diff --git a/localstack-core/localstack/services/events/plugins.py b/localstack-core/localstack/services/events/plugins.py new file mode 100644 index 0000000000000..82570e48cb20b --- /dev/null +++ b/localstack-core/localstack/services/events/plugins.py @@ -0,0 +1,8 @@ +from localstack.packages import Package, package + + +@package(name="event-ruler") +def event_ruler_package() -> Package: + from localstack.services.events.packages import event_ruler_package + + return event_ruler_package diff --git a/tests/aws/services/events/test_events_patterns.py b/tests/aws/services/events/test_events_patterns.py index 63c789cb01c78..1322c029b30ba 100644 --- a/tests/aws/services/events/test_events_patterns.py +++ b/tests/aws/services/events/test_events_patterns.py @@ -22,7 +22,7 @@ COMPLEX_MULTI_KEY_EVENT = os.path.join(REQUEST_TEMPLATE_DIR, "complex_multi_key_event.json") SKIP_LABELS = [ - # Failing exception tests: + # TODO: fix failing exception tests (not yet implemented) "arrays_empty_EXC", "content_numeric_EXC", "content_numeric_operatorcasing_EXC", @@ -31,7 +31,7 @@ "int_nolist_EXC", "operator_case_sensitive_EXC", "string_nolist_EXC", - # Failing tests: + # TODO: fix failing tests for Python event rule engine "complex_or", "content_anything_but_ignorecase", "content_anything_but_ignorecase_list", From 0e01610bb3dde70cf6e5e013f9ab9978d0bafcc9 Mon Sep 17 00:00:00 2001 From: Joel Scheuner Date: Wed, 27 Nov 2024 17:59:15 +0100 Subject: [PATCH 22/38] Re-introduce error analytics for EventBridge rule error (#11935) --- localstack-core/localstack/services/events/provider.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/localstack-core/localstack/services/events/provider.py b/localstack-core/localstack/services/events/provider.py index fe920d765ab05..16923f2d5e03d 100644 --- a/localstack-core/localstack/services/events/provider.py +++ b/localstack-core/localstack/services/events/provider.py @@ -145,7 +145,7 @@ TargetSenderDict, TargetSenderFactory, ) -from localstack.services.events.usage import rule_invocation +from localstack.services.events.usage import rule_error, rule_invocation from localstack.services.events.utils import ( TARGET_ID_PATTERN, extract_event_bus_name, @@ -2165,6 +2165,7 @@ def _process_rules( target_sender.process_event(event_formatted.copy()) rule_invocation.record(target_sender.service) except Exception as error: + rule_error.record(target_sender.service) # Log the error but don't modify the response LOG.info( json.dumps( From 1a46f585c2d41869ec89040eb9a3ca8076ba369e Mon Sep 17 00:00:00 2001 From: Joel Scheuner Date: Thu, 28 Nov 2024 09:18:21 +0100 Subject: [PATCH 23/38] Add lambda ESM analytics (#11883) --- .../lambda_/event_source_mapping/esm_event_processor.py | 7 +++++++ .../event_source_mapping/senders/lambda_sender.py | 3 +++ .../lambda_/event_source_mapping/senders/sender.py | 6 ++++++ localstack-core/localstack/services/lambda_/usage.py | 6 ++++++ tests/unit/utils/analytics/test_usage.py | 9 +++++++++ 5 files changed, 31 insertions(+) create mode 100644 tests/unit/utils/analytics/test_usage.py diff --git a/localstack-core/localstack/services/lambda_/event_source_mapping/esm_event_processor.py b/localstack-core/localstack/services/lambda_/event_source_mapping/esm_event_processor.py index fc860ee74abd5..f70d2e3b78a42 100644 --- a/localstack-core/localstack/services/lambda_/event_source_mapping/esm_event_processor.py +++ b/localstack-core/localstack/services/lambda_/event_source_mapping/esm_event_processor.py @@ -15,6 +15,7 @@ Sender, SenderError, ) +from localstack.services.lambda_.usage import esm_error, esm_invocation LOG = logging.getLogger(__name__) @@ -28,6 +29,11 @@ def __init__(self, sender, logger): self.logger = logger def process_events_batch(self, input_events: list[dict]) -> None: + # analytics + first_event = input_events[0] if input_events else {} + event_source = first_event.get("eventSource") + esm_invocation.record(event_source) + execution_id = uuid.uuid4() # Create a copy of the original input events events = input_events.copy() @@ -69,6 +75,7 @@ def process_events_batch(self, input_events: list[dict]) -> None: ) raise BatchFailureError(error=e.error) from e except Exception as e: + esm_error.record(event_source) LOG.error( "Unhandled exception while processing Lambda event source mapping (ESM) events %s for ESM with execution id %s", events, diff --git a/localstack-core/localstack/services/lambda_/event_source_mapping/senders/lambda_sender.py b/localstack-core/localstack/services/lambda_/event_source_mapping/senders/lambda_sender.py index cbee698a849cf..71911f545a600 100644 --- a/localstack-core/localstack/services/lambda_/event_source_mapping/senders/lambda_sender.py +++ b/localstack-core/localstack/services/lambda_/event_source_mapping/senders/lambda_sender.py @@ -34,6 +34,9 @@ def __init__( self.payload_dict = payload_dict self.report_batch_item_failures = report_batch_item_failures + def event_target(self) -> str: + return "aws:lambda" + def send_events(self, events: list[dict] | dict) -> dict: if self.payload_dict: events = {"Records": events} diff --git a/localstack-core/localstack/services/lambda_/event_source_mapping/senders/sender.py b/localstack-core/localstack/services/lambda_/event_source_mapping/senders/sender.py index 78f656c0e2521..58196bc3d6b02 100644 --- a/localstack-core/localstack/services/lambda_/event_source_mapping/senders/sender.py +++ b/localstack-core/localstack/services/lambda_/event_source_mapping/senders/sender.py @@ -42,3 +42,9 @@ def send_events(self, events: list[dict | str]) -> dict | None: Returns an optional payload with a list of "batchItemFailures" if only part of the batch succeeds. """ pass + + @abstractmethod + def event_target(self) -> str: + """Return the event target metadata (e.g., aws:sqs) + Format analogous to event_source of pollers""" + pass diff --git a/localstack-core/localstack/services/lambda_/usage.py b/localstack-core/localstack/services/lambda_/usage.py index ad432d0ccf792..002082c3e0ff0 100644 --- a/localstack-core/localstack/services/lambda_/usage.py +++ b/localstack-core/localstack/services/lambda_/usage.py @@ -9,3 +9,9 @@ # number of function invocations per Lambda runtime (e.g. python3.7 invoked 10x times, nodejs14.x invoked 3x times, ...) runtime = UsageSetCounter("lambda:invokedruntime") + +# number of event source mapping invocations per source (e.g. aws:sqs, aws:kafka, SelfManagedKafka) +esm_invocation = UsageSetCounter("lambda:esm:invocation") + +# number of event source mapping errors per source (e.g. aws:sqs, aws:kafka, SelfManagedKafka) +esm_error = UsageSetCounter("lambda:esm:error") diff --git a/tests/unit/utils/analytics/test_usage.py b/tests/unit/utils/analytics/test_usage.py new file mode 100644 index 0000000000000..5d7cfd9fe8058 --- /dev/null +++ b/tests/unit/utils/analytics/test_usage.py @@ -0,0 +1,9 @@ +from localstack.utils.analytics.usage import UsageSetCounter + + +def test_set_counter(): + my_feature_counter = UsageSetCounter("lambda:runtime") + my_feature_counter.record("python3.7") + my_feature_counter.record("nodejs16.x") + my_feature_counter.record("nodejs16.x") + assert my_feature_counter.aggregate() == {"python3.7": 1, "nodejs16.x": 2} From 4e78bdf7c65fc3e25081a9bba21d45344d86d7c8 Mon Sep 17 00:00:00 2001 From: Alexander Rashed <2796604+alexrashed@users.noreply.github.com> Date: Thu, 28 Nov 2024 12:10:24 +0100 Subject: [PATCH 24/38] analytics for non-prefixed env var forwarding in CLI (#11946) --- localstack-core/localstack/utils/bootstrap.py | 31 +++++++++++++------ .../bootstrap/test_container_configurators.py | 2 +- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/localstack-core/localstack/utils/bootstrap.py b/localstack-core/localstack/utils/bootstrap.py index b015744891022..fb86899c84a26 100644 --- a/localstack-core/localstack/utils/bootstrap.py +++ b/localstack-core/localstack/utils/bootstrap.py @@ -513,6 +513,7 @@ def config_env_vars(cfg: ContainerConfiguration): if config.LOADED_PROFILES: load_environment(profiles=",".join(config.LOADED_PROFILES), env=profile_env) + non_prefixed_env_vars = [] for env_var in config.CONFIG_ENV_VARS: value = os.environ.get(env_var, None) if value is not None: @@ -521,17 +522,29 @@ def config_env_vars(cfg: ContainerConfiguration): and not env_var.startswith("LOCALSTACK_") and env_var not in profile_env ): - # Show a warning here in case we are directly forwarding an environment variable from - # the system env to the container which has not been prefixed with LOCALSTACK_. - # Suppress the warning for the "CI" env var. - # Suppress the warning if the env var was set from the profile. - LOG.warning( - "Non-prefixed environment variable %(env_var)s is forwarded to the LocalStack container! " - "Please use `LOCALSTACK_%(env_var)s` instead of %(env_var)s to explicitly mark this environment variable to be forwarded form the CLI to the LocalStack Runtime.", - {"env_var": env_var}, - ) + # Collect all env vars that are directly forwarded from the system env + # to the container which has not been prefixed with LOCALSTACK_ here. + # Suppress the "CI" env var. + # Suppress if the env var was set from the profile. + non_prefixed_env_vars.append(env_var) cfg.env_vars[env_var] = value + # collectively log deprecation warnings for non-prefixed sys env vars + if non_prefixed_env_vars: + from localstack.utils.analytics import log + + for non_prefixed_env_var in non_prefixed_env_vars: + # Show a deprecation warning for each individual env var collected above + LOG.warning( + "Non-prefixed environment variable %(env_var)s is forwarded to the LocalStack container! " + "Please use `LOCALSTACK_%(env_var)s` instead of %(env_var)s to explicitly mark this environment variable to be forwarded form the CLI to the LocalStack Runtime.", + {"env_var": non_prefixed_env_var}, + ) + + log.event( + event="non_prefixed_cli_env_vars", payload={"env_vars": non_prefixed_env_vars} + ) + @staticmethod def random_gateway_port(cfg: ContainerConfiguration): """Gets a random port on the host and maps it to the default edge port 4566.""" diff --git a/tests/bootstrap/test_container_configurators.py b/tests/bootstrap/test_container_configurators.py index 66dc0371887c5..d6371d35dc6e4 100644 --- a/tests/bootstrap/test_container_configurators.py +++ b/tests/bootstrap/test_container_configurators.py @@ -191,7 +191,7 @@ def test_container_configurator_no_deprecation_warning_on_prefix( assert "LOCALSTACK_SERVICES" in container.config.env_vars -def test_container_configurator_no_deprecation_warning_for_CI_env_var( +def test_container_configurator_no_deprecation_warning_for_ci_env_var( container_factory, monkeypatch, caplog ): # set the "CI" env var indicating that we are running in a CI environment From 892eb4d062c3b839b8d22427ff752f18eb801c21 Mon Sep 17 00:00:00 2001 From: MEPalma <64580864+MEPalma@users.noreply.github.com> Date: Thu, 28 Nov 2024 12:27:24 +0100 Subject: [PATCH 25/38] StepFunctions: Support Comments in Comparison Composite Statement Lists (#11956) --- .../stepfunctions/asl/antlr/ASLParser.g4 | 2 +- .../asl/antlr/runtime/ASLParser.py | 1270 +++++++++-------- .../statemachines/comments_as_per_docs.json5 | 1 + .../v2/comments/test_comments.py | 4 +- .../v2/comments/test_comments.snapshot.json | 4 +- .../v2/comments/test_comments.validation.json | 6 +- 6 files changed, 649 insertions(+), 638 deletions(-) diff --git a/localstack-core/localstack/services/stepfunctions/asl/antlr/ASLParser.g4 b/localstack-core/localstack/services/stepfunctions/asl/antlr/ASLParser.g4 index ef743236cbb80..3fe2b09564dce 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/antlr/ASLParser.g4 +++ b/localstack-core/localstack/services/stepfunctions/asl/antlr/ASLParser.g4 @@ -315,7 +315,7 @@ comparison_variable_stmt: | comment_decl ; -comparison_composite_stmt: comparison_composite | next_decl | assign_decl; +comparison_composite_stmt: comparison_composite | next_decl | assign_decl | comment_decl; comparison_composite // TODO: this allows for Next definitions in nested choice_rules, is this supported at parse time? diff --git a/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParser.py b/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParser.py index d3589f2d0c1c9..22386a4edcce7 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParser.py +++ b/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParser.py @@ -10,7 +10,7 @@ def serializedATN(): return [ - 4,1,160,1228,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6, + 4,1,160,1229,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6, 7,6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,13,7, 13,2,14,7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,19,2, 20,7,20,2,21,7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,2,26,7, @@ -76,188 +76,188 @@ def serializedATN(): 1,62,1,63,1,63,1,63,1,63,4,63,782,8,63,11,63,12,63,783,1,63,1,63, 1,63,1,63,1,63,1,63,5,63,792,8,63,10,63,12,63,795,9,63,1,63,1,63, 3,63,799,8,63,1,64,1,64,1,64,1,64,1,64,3,64,806,8,64,1,65,1,65,1, - 65,3,65,811,8,65,1,66,1,66,1,66,1,66,1,66,1,66,1,66,5,66,820,8,66, - 10,66,12,66,823,9,66,1,66,1,66,3,66,827,8,66,1,67,1,67,1,67,1,67, - 1,67,1,67,1,67,1,67,1,67,3,67,838,8,67,1,68,1,68,1,68,1,68,1,68, - 1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,3,68,854,8,68,1,69, - 1,69,1,69,1,69,1,69,1,69,5,69,862,8,69,10,69,12,69,865,9,69,1,69, - 1,69,1,70,1,70,1,70,1,70,1,70,1,70,5,70,875,8,70,10,70,12,70,878, - 9,70,1,70,1,70,1,71,1,71,1,71,1,71,3,71,886,8,71,1,72,1,72,1,72, - 1,72,1,72,1,72,5,72,894,8,72,10,72,12,72,897,9,72,1,72,1,72,1,73, - 1,73,3,73,903,8,73,1,74,1,74,1,74,1,74,1,75,1,75,1,76,1,76,1,76, - 1,76,1,77,1,77,1,78,1,78,1,78,1,78,1,78,1,78,5,78,923,8,78,10,78, - 12,78,926,9,78,1,78,1,78,1,79,1,79,1,79,1,79,3,79,934,8,79,1,80, - 1,80,1,80,1,80,1,81,1,81,1,81,1,81,1,81,1,81,5,81,946,8,81,10,81, - 12,81,949,9,81,1,81,1,81,1,82,1,82,1,82,1,82,3,82,957,8,82,1,83, - 1,83,1,83,1,83,1,83,1,83,5,83,965,8,83,10,83,12,83,968,9,83,1,83, - 1,83,1,84,1,84,1,84,1,84,1,84,3,84,977,8,84,1,85,1,85,1,85,1,85, - 1,86,1,86,1,86,1,86,1,87,1,87,1,87,1,87,1,87,1,87,5,87,993,8,87, - 10,87,12,87,996,9,87,1,87,1,87,1,88,1,88,1,88,1,88,1,88,1,88,3,88, - 1006,8,88,1,89,1,89,1,89,1,89,1,89,1,89,3,89,1014,8,89,1,90,1,90, - 1,90,1,90,1,90,1,90,3,90,1022,8,90,1,91,1,91,1,91,1,91,1,91,1,91, - 3,91,1030,8,91,1,92,1,92,1,92,1,92,1,92,1,92,3,92,1038,8,92,1,93, - 1,93,1,93,1,93,1,93,1,93,3,93,1046,8,93,1,94,1,94,1,94,1,94,1,95, - 1,95,1,95,1,95,1,95,1,95,5,95,1058,8,95,10,95,12,95,1061,9,95,1, - 95,1,95,1,96,1,96,3,96,1067,8,96,1,97,1,97,1,97,1,97,1,97,1,97,5, - 97,1075,8,97,10,97,12,97,1078,9,97,3,97,1080,8,97,1,97,1,97,1,98, - 1,98,1,98,1,98,5,98,1088,8,98,10,98,12,98,1091,9,98,1,98,1,98,1, - 99,1,99,1,99,1,99,1,99,1,99,1,99,3,99,1102,8,99,1,100,1,100,1,100, - 1,100,1,100,1,100,5,100,1110,8,100,10,100,12,100,1113,9,100,1,100, - 1,100,1,101,1,101,1,101,1,101,1,102,1,102,1,102,1,102,1,103,1,103, - 1,103,1,103,1,104,1,104,1,104,1,104,1,105,1,105,1,105,1,105,1,106, - 1,106,1,106,1,106,1,106,1,106,5,106,1143,8,106,10,106,12,106,1146, - 9,106,3,106,1148,8,106,1,106,1,106,1,107,1,107,1,107,1,107,5,107, - 1156,8,107,10,107,12,107,1159,9,107,1,107,1,107,1,108,1,108,1,108, - 1,108,1,108,1,108,3,108,1169,8,108,1,109,1,109,1,110,1,110,1,111, - 1,111,1,112,1,112,3,112,1179,8,112,1,113,1,113,1,113,1,113,5,113, - 1185,8,113,10,113,12,113,1188,9,113,1,113,1,113,1,113,1,113,3,113, - 1194,8,113,1,114,1,114,1,114,1,114,1,115,1,115,1,115,1,115,5,115, - 1204,8,115,10,115,12,115,1207,9,115,1,115,1,115,1,115,1,115,3,115, - 1213,8,115,1,116,1,116,1,116,1,116,1,116,1,116,1,116,1,116,1,116, - 3,116,1224,8,116,1,117,1,117,1,117,0,0,118,0,2,4,6,8,10,12,14,16, - 18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60, - 62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102, - 104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134, - 136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,166, - 168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198, - 200,202,204,206,208,210,212,214,216,218,220,222,224,226,228,230, - 232,234,0,10,1,0,130,131,1,0,7,8,1,0,16,23,1,0,81,82,1,0,158,159, - 1,0,126,127,3,0,30,37,39,48,50,70,3,0,29,29,38,38,49,49,1,0,135, - 150,6,0,10,13,15,115,117,117,119,129,132,135,137,157,1309,0,236, - 1,0,0,0,2,239,1,0,0,0,4,256,1,0,0,0,6,258,1,0,0,0,8,262,1,0,0,0, - 10,266,1,0,0,0,12,270,1,0,0,0,14,321,1,0,0,0,16,323,1,0,0,0,18,336, - 1,0,0,0,20,338,1,0,0,0,22,342,1,0,0,0,24,353,1,0,0,0,26,357,1,0, - 0,0,28,361,1,0,0,0,30,377,1,0,0,0,32,379,1,0,0,0,34,383,1,0,0,0, - 36,401,1,0,0,0,38,403,1,0,0,0,40,407,1,0,0,0,42,417,1,0,0,0,44,428, - 1,0,0,0,46,436,1,0,0,0,48,447,1,0,0,0,50,455,1,0,0,0,52,463,1,0, - 0,0,54,471,1,0,0,0,56,479,1,0,0,0,58,487,1,0,0,0,60,498,1,0,0,0, - 62,506,1,0,0,0,64,514,1,0,0,0,66,516,1,0,0,0,68,520,1,0,0,0,70,530, - 1,0,0,0,72,538,1,0,0,0,74,546,1,0,0,0,76,554,1,0,0,0,78,556,1,0, - 0,0,80,571,1,0,0,0,82,589,1,0,0,0,84,604,1,0,0,0,86,609,1,0,0,0, - 88,616,1,0,0,0,90,618,1,0,0,0,92,635,1,0,0,0,94,637,1,0,0,0,96,652, - 1,0,0,0,98,669,1,0,0,0,100,674,1,0,0,0,102,689,1,0,0,0,104,697,1, - 0,0,0,106,705,1,0,0,0,108,707,1,0,0,0,110,724,1,0,0,0,112,726,1, - 0,0,0,114,733,1,0,0,0,116,748,1,0,0,0,118,756,1,0,0,0,120,758,1, - 0,0,0,122,762,1,0,0,0,124,764,1,0,0,0,126,798,1,0,0,0,128,805,1, - 0,0,0,130,810,1,0,0,0,132,812,1,0,0,0,134,837,1,0,0,0,136,853,1, - 0,0,0,138,855,1,0,0,0,140,868,1,0,0,0,142,885,1,0,0,0,144,887,1, - 0,0,0,146,902,1,0,0,0,148,904,1,0,0,0,150,908,1,0,0,0,152,910,1, - 0,0,0,154,914,1,0,0,0,156,916,1,0,0,0,158,933,1,0,0,0,160,935,1, - 0,0,0,162,939,1,0,0,0,164,956,1,0,0,0,166,958,1,0,0,0,168,976,1, - 0,0,0,170,978,1,0,0,0,172,982,1,0,0,0,174,986,1,0,0,0,176,1005,1, - 0,0,0,178,1013,1,0,0,0,180,1021,1,0,0,0,182,1029,1,0,0,0,184,1037, - 1,0,0,0,186,1045,1,0,0,0,188,1047,1,0,0,0,190,1051,1,0,0,0,192,1066, - 1,0,0,0,194,1068,1,0,0,0,196,1083,1,0,0,0,198,1101,1,0,0,0,200,1103, - 1,0,0,0,202,1116,1,0,0,0,204,1120,1,0,0,0,206,1124,1,0,0,0,208,1128, - 1,0,0,0,210,1132,1,0,0,0,212,1136,1,0,0,0,214,1151,1,0,0,0,216,1168, - 1,0,0,0,218,1170,1,0,0,0,220,1172,1,0,0,0,222,1174,1,0,0,0,224,1178, - 1,0,0,0,226,1193,1,0,0,0,228,1195,1,0,0,0,230,1212,1,0,0,0,232,1223, - 1,0,0,0,234,1225,1,0,0,0,236,237,3,2,1,0,237,238,5,0,0,1,238,1,1, - 0,0,0,239,240,5,5,0,0,240,245,3,4,2,0,241,242,5,1,0,0,242,244,3, - 4,2,0,243,241,1,0,0,0,244,247,1,0,0,0,245,243,1,0,0,0,245,246,1, - 0,0,0,246,248,1,0,0,0,247,245,1,0,0,0,248,249,5,6,0,0,249,3,1,0, - 0,0,250,257,3,8,4,0,251,257,3,10,5,0,252,257,3,12,6,0,253,257,3, - 6,3,0,254,257,3,16,8,0,255,257,3,70,35,0,256,250,1,0,0,0,256,251, - 1,0,0,0,256,252,1,0,0,0,256,253,1,0,0,0,256,254,1,0,0,0,256,255, - 1,0,0,0,257,5,1,0,0,0,258,259,5,12,0,0,259,260,5,2,0,0,260,261,3, - 234,117,0,261,7,1,0,0,0,262,263,5,10,0,0,263,264,5,2,0,0,264,265, - 3,234,117,0,265,9,1,0,0,0,266,267,5,14,0,0,267,268,5,2,0,0,268,269, - 3,234,117,0,269,11,1,0,0,0,270,271,5,129,0,0,271,272,5,2,0,0,272, - 273,7,0,0,0,273,13,1,0,0,0,274,322,3,8,4,0,275,322,3,12,6,0,276, - 322,3,24,12,0,277,322,3,30,15,0,278,322,3,28,14,0,279,322,3,26,13, - 0,280,322,3,32,16,0,281,322,3,34,17,0,282,322,3,36,18,0,283,322, - 3,38,19,0,284,322,3,40,20,0,285,322,3,124,62,0,286,322,3,42,21,0, - 287,322,3,44,22,0,288,322,3,46,23,0,289,322,3,48,24,0,290,322,3, - 50,25,0,291,322,3,52,26,0,292,322,3,54,27,0,293,322,3,56,28,0,294, - 322,3,58,29,0,295,322,3,60,30,0,296,322,3,140,70,0,297,322,3,156, - 78,0,298,322,3,160,80,0,299,322,3,162,81,0,300,322,3,62,31,0,301, - 322,3,64,32,0,302,322,3,70,35,0,303,322,3,72,36,0,304,322,3,74,37, - 0,305,322,3,76,38,0,306,322,3,138,69,0,307,322,3,66,33,0,308,322, - 3,194,97,0,309,322,3,212,106,0,310,322,3,120,60,0,311,322,3,180, - 90,0,312,322,3,182,91,0,313,322,3,184,92,0,314,322,3,186,93,0,315, - 322,3,188,94,0,316,322,3,190,95,0,317,322,3,90,45,0,318,322,3,106, - 53,0,319,322,3,108,54,0,320,322,3,68,34,0,321,274,1,0,0,0,321,275, - 1,0,0,0,321,276,1,0,0,0,321,277,1,0,0,0,321,278,1,0,0,0,321,279, - 1,0,0,0,321,280,1,0,0,0,321,281,1,0,0,0,321,282,1,0,0,0,321,283, - 1,0,0,0,321,284,1,0,0,0,321,285,1,0,0,0,321,286,1,0,0,0,321,287, - 1,0,0,0,321,288,1,0,0,0,321,289,1,0,0,0,321,290,1,0,0,0,321,291, - 1,0,0,0,321,292,1,0,0,0,321,293,1,0,0,0,321,294,1,0,0,0,321,295, - 1,0,0,0,321,296,1,0,0,0,321,297,1,0,0,0,321,298,1,0,0,0,321,299, - 1,0,0,0,321,300,1,0,0,0,321,301,1,0,0,0,321,302,1,0,0,0,321,303, - 1,0,0,0,321,304,1,0,0,0,321,305,1,0,0,0,321,306,1,0,0,0,321,307, - 1,0,0,0,321,308,1,0,0,0,321,309,1,0,0,0,321,310,1,0,0,0,321,311, - 1,0,0,0,321,312,1,0,0,0,321,313,1,0,0,0,321,314,1,0,0,0,321,315, - 1,0,0,0,321,316,1,0,0,0,321,317,1,0,0,0,321,318,1,0,0,0,321,319, - 1,0,0,0,321,320,1,0,0,0,322,15,1,0,0,0,323,324,5,11,0,0,324,325, - 5,2,0,0,325,326,5,5,0,0,326,331,3,20,10,0,327,328,5,1,0,0,328,330, - 3,20,10,0,329,327,1,0,0,0,330,333,1,0,0,0,331,329,1,0,0,0,331,332, - 1,0,0,0,332,334,1,0,0,0,333,331,1,0,0,0,334,335,5,6,0,0,335,17,1, - 0,0,0,336,337,3,234,117,0,337,19,1,0,0,0,338,339,3,18,9,0,339,340, - 5,2,0,0,340,341,3,22,11,0,341,21,1,0,0,0,342,343,5,5,0,0,343,348, - 3,14,7,0,344,345,5,1,0,0,345,347,3,14,7,0,346,344,1,0,0,0,347,350, - 1,0,0,0,348,346,1,0,0,0,348,349,1,0,0,0,349,351,1,0,0,0,350,348, - 1,0,0,0,351,352,5,6,0,0,352,23,1,0,0,0,353,354,5,15,0,0,354,355, - 5,2,0,0,355,356,3,122,61,0,356,25,1,0,0,0,357,358,5,113,0,0,358, - 359,5,2,0,0,359,360,3,234,117,0,360,27,1,0,0,0,361,362,5,90,0,0, - 362,363,5,2,0,0,363,364,3,234,117,0,364,29,1,0,0,0,365,366,5,91, - 0,0,366,367,5,2,0,0,367,378,3,78,39,0,368,369,5,91,0,0,369,370,5, - 2,0,0,370,378,5,152,0,0,371,372,5,91,0,0,372,375,5,2,0,0,373,376, - 5,9,0,0,374,376,3,234,117,0,375,373,1,0,0,0,375,374,1,0,0,0,376, - 378,1,0,0,0,377,365,1,0,0,0,377,368,1,0,0,0,377,371,1,0,0,0,378, - 31,1,0,0,0,379,380,5,96,0,0,380,381,5,2,0,0,381,382,3,232,116,0, - 382,33,1,0,0,0,383,384,5,95,0,0,384,387,5,2,0,0,385,388,5,9,0,0, - 386,388,3,234,117,0,387,385,1,0,0,0,387,386,1,0,0,0,388,35,1,0,0, - 0,389,390,5,92,0,0,390,391,5,2,0,0,391,402,3,78,39,0,392,393,5,92, - 0,0,393,394,5,2,0,0,394,402,5,152,0,0,395,396,5,92,0,0,396,399,5, - 2,0,0,397,400,5,9,0,0,398,400,3,234,117,0,399,397,1,0,0,0,399,398, - 1,0,0,0,400,402,1,0,0,0,401,389,1,0,0,0,401,392,1,0,0,0,401,395, - 1,0,0,0,402,37,1,0,0,0,403,404,5,114,0,0,404,405,5,2,0,0,405,406, - 7,1,0,0,406,39,1,0,0,0,407,408,5,27,0,0,408,409,5,2,0,0,409,410, - 3,234,117,0,410,41,1,0,0,0,411,412,5,117,0,0,412,413,5,2,0,0,413, - 418,5,156,0,0,414,415,5,117,0,0,415,416,5,2,0,0,416,418,3,234,117, - 0,417,411,1,0,0,0,417,414,1,0,0,0,418,43,1,0,0,0,419,420,5,118,0, - 0,420,421,5,2,0,0,421,429,3,78,39,0,422,423,5,118,0,0,423,424,5, - 2,0,0,424,429,5,153,0,0,425,426,5,118,0,0,426,427,5,2,0,0,427,429, - 5,155,0,0,428,419,1,0,0,0,428,422,1,0,0,0,428,425,1,0,0,0,429,45, - 1,0,0,0,430,431,5,115,0,0,431,432,5,2,0,0,432,437,5,156,0,0,433, - 434,5,115,0,0,434,435,5,2,0,0,435,437,3,234,117,0,436,430,1,0,0, - 0,436,433,1,0,0,0,437,47,1,0,0,0,438,439,5,116,0,0,439,440,5,2,0, - 0,440,448,3,78,39,0,441,442,5,116,0,0,442,443,5,2,0,0,443,448,5, - 153,0,0,444,445,5,116,0,0,445,446,5,2,0,0,446,448,5,155,0,0,447, - 438,1,0,0,0,447,441,1,0,0,0,447,444,1,0,0,0,448,49,1,0,0,0,449,450, - 5,72,0,0,450,451,5,2,0,0,451,456,5,156,0,0,452,453,5,72,0,0,453, - 454,5,2,0,0,454,456,5,158,0,0,455,449,1,0,0,0,455,452,1,0,0,0,456, - 51,1,0,0,0,457,458,5,71,0,0,458,459,5,2,0,0,459,464,3,78,39,0,460, - 461,5,71,0,0,461,462,5,2,0,0,462,464,3,234,117,0,463,457,1,0,0,0, - 463,460,1,0,0,0,464,53,1,0,0,0,465,466,5,74,0,0,466,467,5,2,0,0, - 467,472,5,156,0,0,468,469,5,74,0,0,469,470,5,2,0,0,470,472,3,234, - 117,0,471,465,1,0,0,0,471,468,1,0,0,0,472,55,1,0,0,0,473,474,5,73, - 0,0,474,475,5,2,0,0,475,480,3,78,39,0,476,477,5,73,0,0,477,478,5, - 2,0,0,478,480,3,234,117,0,479,473,1,0,0,0,479,476,1,0,0,0,480,57, - 1,0,0,0,481,482,5,93,0,0,482,483,5,2,0,0,483,488,3,116,58,0,484, - 485,5,93,0,0,485,486,5,2,0,0,486,488,5,156,0,0,487,481,1,0,0,0,487, - 484,1,0,0,0,488,59,1,0,0,0,489,490,5,94,0,0,490,491,5,2,0,0,491, - 499,5,152,0,0,492,493,5,94,0,0,493,494,5,2,0,0,494,499,3,78,39,0, - 495,496,5,94,0,0,496,497,5,2,0,0,497,499,3,234,117,0,498,489,1,0, - 0,0,498,492,1,0,0,0,498,495,1,0,0,0,499,61,1,0,0,0,500,501,5,89, - 0,0,501,502,5,2,0,0,502,507,5,156,0,0,503,504,5,89,0,0,504,505,5, - 2,0,0,505,507,5,158,0,0,506,500,1,0,0,0,506,503,1,0,0,0,507,63,1, - 0,0,0,508,509,5,88,0,0,509,510,5,2,0,0,510,515,3,78,39,0,511,512, - 5,88,0,0,512,513,5,2,0,0,513,515,5,153,0,0,514,508,1,0,0,0,514,511, - 1,0,0,0,515,65,1,0,0,0,516,517,5,97,0,0,517,518,5,2,0,0,518,519, - 3,80,40,0,519,67,1,0,0,0,520,521,5,98,0,0,521,522,5,2,0,0,522,523, - 3,80,40,0,523,69,1,0,0,0,524,525,5,75,0,0,525,526,5,2,0,0,526,531, - 5,156,0,0,527,528,5,75,0,0,528,529,5,2,0,0,529,531,5,158,0,0,530, - 524,1,0,0,0,530,527,1,0,0,0,531,71,1,0,0,0,532,533,5,76,0,0,533, - 534,5,2,0,0,534,539,3,78,39,0,535,536,5,76,0,0,536,537,5,2,0,0,537, - 539,5,153,0,0,538,532,1,0,0,0,538,535,1,0,0,0,539,73,1,0,0,0,540, - 541,5,77,0,0,541,542,5,2,0,0,542,547,5,156,0,0,543,544,5,77,0,0, - 544,545,5,2,0,0,545,547,5,158,0,0,546,540,1,0,0,0,546,543,1,0,0, - 0,547,75,1,0,0,0,548,549,5,78,0,0,549,550,5,2,0,0,550,555,3,78,39, - 0,551,552,5,78,0,0,552,553,5,2,0,0,553,555,5,153,0,0,554,548,1,0, - 0,0,554,551,1,0,0,0,555,77,1,0,0,0,556,557,5,154,0,0,557,79,1,0, - 0,0,558,559,5,5,0,0,559,564,3,82,41,0,560,561,5,1,0,0,561,563,3, - 82,41,0,562,560,1,0,0,0,563,566,1,0,0,0,564,562,1,0,0,0,564,565, + 65,1,65,3,65,812,8,65,1,66,1,66,1,66,1,66,1,66,1,66,1,66,5,66,821, + 8,66,10,66,12,66,824,9,66,1,66,1,66,3,66,828,8,66,1,67,1,67,1,67, + 1,67,1,67,1,67,1,67,1,67,1,67,3,67,839,8,67,1,68,1,68,1,68,1,68, + 1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,3,68,855,8,68, + 1,69,1,69,1,69,1,69,1,69,1,69,5,69,863,8,69,10,69,12,69,866,9,69, + 1,69,1,69,1,70,1,70,1,70,1,70,1,70,1,70,5,70,876,8,70,10,70,12,70, + 879,9,70,1,70,1,70,1,71,1,71,1,71,1,71,3,71,887,8,71,1,72,1,72,1, + 72,1,72,1,72,1,72,5,72,895,8,72,10,72,12,72,898,9,72,1,72,1,72,1, + 73,1,73,3,73,904,8,73,1,74,1,74,1,74,1,74,1,75,1,75,1,76,1,76,1, + 76,1,76,1,77,1,77,1,78,1,78,1,78,1,78,1,78,1,78,5,78,924,8,78,10, + 78,12,78,927,9,78,1,78,1,78,1,79,1,79,1,79,1,79,3,79,935,8,79,1, + 80,1,80,1,80,1,80,1,81,1,81,1,81,1,81,1,81,1,81,5,81,947,8,81,10, + 81,12,81,950,9,81,1,81,1,81,1,82,1,82,1,82,1,82,3,82,958,8,82,1, + 83,1,83,1,83,1,83,1,83,1,83,5,83,966,8,83,10,83,12,83,969,9,83,1, + 83,1,83,1,84,1,84,1,84,1,84,1,84,3,84,978,8,84,1,85,1,85,1,85,1, + 85,1,86,1,86,1,86,1,86,1,87,1,87,1,87,1,87,1,87,1,87,5,87,994,8, + 87,10,87,12,87,997,9,87,1,87,1,87,1,88,1,88,1,88,1,88,1,88,1,88, + 3,88,1007,8,88,1,89,1,89,1,89,1,89,1,89,1,89,3,89,1015,8,89,1,90, + 1,90,1,90,1,90,1,90,1,90,3,90,1023,8,90,1,91,1,91,1,91,1,91,1,91, + 1,91,3,91,1031,8,91,1,92,1,92,1,92,1,92,1,92,1,92,3,92,1039,8,92, + 1,93,1,93,1,93,1,93,1,93,1,93,3,93,1047,8,93,1,94,1,94,1,94,1,94, + 1,95,1,95,1,95,1,95,1,95,1,95,5,95,1059,8,95,10,95,12,95,1062,9, + 95,1,95,1,95,1,96,1,96,3,96,1068,8,96,1,97,1,97,1,97,1,97,1,97,1, + 97,5,97,1076,8,97,10,97,12,97,1079,9,97,3,97,1081,8,97,1,97,1,97, + 1,98,1,98,1,98,1,98,5,98,1089,8,98,10,98,12,98,1092,9,98,1,98,1, + 98,1,99,1,99,1,99,1,99,1,99,1,99,1,99,3,99,1103,8,99,1,100,1,100, + 1,100,1,100,1,100,1,100,5,100,1111,8,100,10,100,12,100,1114,9,100, + 1,100,1,100,1,101,1,101,1,101,1,101,1,102,1,102,1,102,1,102,1,103, + 1,103,1,103,1,103,1,104,1,104,1,104,1,104,1,105,1,105,1,105,1,105, + 1,106,1,106,1,106,1,106,1,106,1,106,5,106,1144,8,106,10,106,12,106, + 1147,9,106,3,106,1149,8,106,1,106,1,106,1,107,1,107,1,107,1,107, + 5,107,1157,8,107,10,107,12,107,1160,9,107,1,107,1,107,1,108,1,108, + 1,108,1,108,1,108,1,108,3,108,1170,8,108,1,109,1,109,1,110,1,110, + 1,111,1,111,1,112,1,112,3,112,1180,8,112,1,113,1,113,1,113,1,113, + 5,113,1186,8,113,10,113,12,113,1189,9,113,1,113,1,113,1,113,1,113, + 3,113,1195,8,113,1,114,1,114,1,114,1,114,1,115,1,115,1,115,1,115, + 5,115,1205,8,115,10,115,12,115,1208,9,115,1,115,1,115,1,115,1,115, + 3,115,1214,8,115,1,116,1,116,1,116,1,116,1,116,1,116,1,116,1,116, + 1,116,3,116,1225,8,116,1,117,1,117,1,117,0,0,118,0,2,4,6,8,10,12, + 14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56, + 58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100, + 102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132, + 134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164, + 166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196, + 198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228, + 230,232,234,0,10,1,0,130,131,1,0,7,8,1,0,16,23,1,0,81,82,1,0,158, + 159,1,0,126,127,3,0,30,37,39,48,50,70,3,0,29,29,38,38,49,49,1,0, + 135,150,6,0,10,13,15,115,117,117,119,129,132,135,137,157,1311,0, + 236,1,0,0,0,2,239,1,0,0,0,4,256,1,0,0,0,6,258,1,0,0,0,8,262,1,0, + 0,0,10,266,1,0,0,0,12,270,1,0,0,0,14,321,1,0,0,0,16,323,1,0,0,0, + 18,336,1,0,0,0,20,338,1,0,0,0,22,342,1,0,0,0,24,353,1,0,0,0,26,357, + 1,0,0,0,28,361,1,0,0,0,30,377,1,0,0,0,32,379,1,0,0,0,34,383,1,0, + 0,0,36,401,1,0,0,0,38,403,1,0,0,0,40,407,1,0,0,0,42,417,1,0,0,0, + 44,428,1,0,0,0,46,436,1,0,0,0,48,447,1,0,0,0,50,455,1,0,0,0,52,463, + 1,0,0,0,54,471,1,0,0,0,56,479,1,0,0,0,58,487,1,0,0,0,60,498,1,0, + 0,0,62,506,1,0,0,0,64,514,1,0,0,0,66,516,1,0,0,0,68,520,1,0,0,0, + 70,530,1,0,0,0,72,538,1,0,0,0,74,546,1,0,0,0,76,554,1,0,0,0,78,556, + 1,0,0,0,80,571,1,0,0,0,82,589,1,0,0,0,84,604,1,0,0,0,86,609,1,0, + 0,0,88,616,1,0,0,0,90,618,1,0,0,0,92,635,1,0,0,0,94,637,1,0,0,0, + 96,652,1,0,0,0,98,669,1,0,0,0,100,674,1,0,0,0,102,689,1,0,0,0,104, + 697,1,0,0,0,106,705,1,0,0,0,108,707,1,0,0,0,110,724,1,0,0,0,112, + 726,1,0,0,0,114,733,1,0,0,0,116,748,1,0,0,0,118,756,1,0,0,0,120, + 758,1,0,0,0,122,762,1,0,0,0,124,764,1,0,0,0,126,798,1,0,0,0,128, + 805,1,0,0,0,130,811,1,0,0,0,132,813,1,0,0,0,134,838,1,0,0,0,136, + 854,1,0,0,0,138,856,1,0,0,0,140,869,1,0,0,0,142,886,1,0,0,0,144, + 888,1,0,0,0,146,903,1,0,0,0,148,905,1,0,0,0,150,909,1,0,0,0,152, + 911,1,0,0,0,154,915,1,0,0,0,156,917,1,0,0,0,158,934,1,0,0,0,160, + 936,1,0,0,0,162,940,1,0,0,0,164,957,1,0,0,0,166,959,1,0,0,0,168, + 977,1,0,0,0,170,979,1,0,0,0,172,983,1,0,0,0,174,987,1,0,0,0,176, + 1006,1,0,0,0,178,1014,1,0,0,0,180,1022,1,0,0,0,182,1030,1,0,0,0, + 184,1038,1,0,0,0,186,1046,1,0,0,0,188,1048,1,0,0,0,190,1052,1,0, + 0,0,192,1067,1,0,0,0,194,1069,1,0,0,0,196,1084,1,0,0,0,198,1102, + 1,0,0,0,200,1104,1,0,0,0,202,1117,1,0,0,0,204,1121,1,0,0,0,206,1125, + 1,0,0,0,208,1129,1,0,0,0,210,1133,1,0,0,0,212,1137,1,0,0,0,214,1152, + 1,0,0,0,216,1169,1,0,0,0,218,1171,1,0,0,0,220,1173,1,0,0,0,222,1175, + 1,0,0,0,224,1179,1,0,0,0,226,1194,1,0,0,0,228,1196,1,0,0,0,230,1213, + 1,0,0,0,232,1224,1,0,0,0,234,1226,1,0,0,0,236,237,3,2,1,0,237,238, + 5,0,0,1,238,1,1,0,0,0,239,240,5,5,0,0,240,245,3,4,2,0,241,242,5, + 1,0,0,242,244,3,4,2,0,243,241,1,0,0,0,244,247,1,0,0,0,245,243,1, + 0,0,0,245,246,1,0,0,0,246,248,1,0,0,0,247,245,1,0,0,0,248,249,5, + 6,0,0,249,3,1,0,0,0,250,257,3,8,4,0,251,257,3,10,5,0,252,257,3,12, + 6,0,253,257,3,6,3,0,254,257,3,16,8,0,255,257,3,70,35,0,256,250,1, + 0,0,0,256,251,1,0,0,0,256,252,1,0,0,0,256,253,1,0,0,0,256,254,1, + 0,0,0,256,255,1,0,0,0,257,5,1,0,0,0,258,259,5,12,0,0,259,260,5,2, + 0,0,260,261,3,234,117,0,261,7,1,0,0,0,262,263,5,10,0,0,263,264,5, + 2,0,0,264,265,3,234,117,0,265,9,1,0,0,0,266,267,5,14,0,0,267,268, + 5,2,0,0,268,269,3,234,117,0,269,11,1,0,0,0,270,271,5,129,0,0,271, + 272,5,2,0,0,272,273,7,0,0,0,273,13,1,0,0,0,274,322,3,8,4,0,275,322, + 3,12,6,0,276,322,3,24,12,0,277,322,3,30,15,0,278,322,3,28,14,0,279, + 322,3,26,13,0,280,322,3,32,16,0,281,322,3,34,17,0,282,322,3,36,18, + 0,283,322,3,38,19,0,284,322,3,40,20,0,285,322,3,124,62,0,286,322, + 3,42,21,0,287,322,3,44,22,0,288,322,3,46,23,0,289,322,3,48,24,0, + 290,322,3,50,25,0,291,322,3,52,26,0,292,322,3,54,27,0,293,322,3, + 56,28,0,294,322,3,58,29,0,295,322,3,60,30,0,296,322,3,140,70,0,297, + 322,3,156,78,0,298,322,3,160,80,0,299,322,3,162,81,0,300,322,3,62, + 31,0,301,322,3,64,32,0,302,322,3,70,35,0,303,322,3,72,36,0,304,322, + 3,74,37,0,305,322,3,76,38,0,306,322,3,138,69,0,307,322,3,66,33,0, + 308,322,3,194,97,0,309,322,3,212,106,0,310,322,3,120,60,0,311,322, + 3,180,90,0,312,322,3,182,91,0,313,322,3,184,92,0,314,322,3,186,93, + 0,315,322,3,188,94,0,316,322,3,190,95,0,317,322,3,90,45,0,318,322, + 3,106,53,0,319,322,3,108,54,0,320,322,3,68,34,0,321,274,1,0,0,0, + 321,275,1,0,0,0,321,276,1,0,0,0,321,277,1,0,0,0,321,278,1,0,0,0, + 321,279,1,0,0,0,321,280,1,0,0,0,321,281,1,0,0,0,321,282,1,0,0,0, + 321,283,1,0,0,0,321,284,1,0,0,0,321,285,1,0,0,0,321,286,1,0,0,0, + 321,287,1,0,0,0,321,288,1,0,0,0,321,289,1,0,0,0,321,290,1,0,0,0, + 321,291,1,0,0,0,321,292,1,0,0,0,321,293,1,0,0,0,321,294,1,0,0,0, + 321,295,1,0,0,0,321,296,1,0,0,0,321,297,1,0,0,0,321,298,1,0,0,0, + 321,299,1,0,0,0,321,300,1,0,0,0,321,301,1,0,0,0,321,302,1,0,0,0, + 321,303,1,0,0,0,321,304,1,0,0,0,321,305,1,0,0,0,321,306,1,0,0,0, + 321,307,1,0,0,0,321,308,1,0,0,0,321,309,1,0,0,0,321,310,1,0,0,0, + 321,311,1,0,0,0,321,312,1,0,0,0,321,313,1,0,0,0,321,314,1,0,0,0, + 321,315,1,0,0,0,321,316,1,0,0,0,321,317,1,0,0,0,321,318,1,0,0,0, + 321,319,1,0,0,0,321,320,1,0,0,0,322,15,1,0,0,0,323,324,5,11,0,0, + 324,325,5,2,0,0,325,326,5,5,0,0,326,331,3,20,10,0,327,328,5,1,0, + 0,328,330,3,20,10,0,329,327,1,0,0,0,330,333,1,0,0,0,331,329,1,0, + 0,0,331,332,1,0,0,0,332,334,1,0,0,0,333,331,1,0,0,0,334,335,5,6, + 0,0,335,17,1,0,0,0,336,337,3,234,117,0,337,19,1,0,0,0,338,339,3, + 18,9,0,339,340,5,2,0,0,340,341,3,22,11,0,341,21,1,0,0,0,342,343, + 5,5,0,0,343,348,3,14,7,0,344,345,5,1,0,0,345,347,3,14,7,0,346,344, + 1,0,0,0,347,350,1,0,0,0,348,346,1,0,0,0,348,349,1,0,0,0,349,351, + 1,0,0,0,350,348,1,0,0,0,351,352,5,6,0,0,352,23,1,0,0,0,353,354,5, + 15,0,0,354,355,5,2,0,0,355,356,3,122,61,0,356,25,1,0,0,0,357,358, + 5,113,0,0,358,359,5,2,0,0,359,360,3,234,117,0,360,27,1,0,0,0,361, + 362,5,90,0,0,362,363,5,2,0,0,363,364,3,234,117,0,364,29,1,0,0,0, + 365,366,5,91,0,0,366,367,5,2,0,0,367,378,3,78,39,0,368,369,5,91, + 0,0,369,370,5,2,0,0,370,378,5,152,0,0,371,372,5,91,0,0,372,375,5, + 2,0,0,373,376,5,9,0,0,374,376,3,234,117,0,375,373,1,0,0,0,375,374, + 1,0,0,0,376,378,1,0,0,0,377,365,1,0,0,0,377,368,1,0,0,0,377,371, + 1,0,0,0,378,31,1,0,0,0,379,380,5,96,0,0,380,381,5,2,0,0,381,382, + 3,232,116,0,382,33,1,0,0,0,383,384,5,95,0,0,384,387,5,2,0,0,385, + 388,5,9,0,0,386,388,3,234,117,0,387,385,1,0,0,0,387,386,1,0,0,0, + 388,35,1,0,0,0,389,390,5,92,0,0,390,391,5,2,0,0,391,402,3,78,39, + 0,392,393,5,92,0,0,393,394,5,2,0,0,394,402,5,152,0,0,395,396,5,92, + 0,0,396,399,5,2,0,0,397,400,5,9,0,0,398,400,3,234,117,0,399,397, + 1,0,0,0,399,398,1,0,0,0,400,402,1,0,0,0,401,389,1,0,0,0,401,392, + 1,0,0,0,401,395,1,0,0,0,402,37,1,0,0,0,403,404,5,114,0,0,404,405, + 5,2,0,0,405,406,7,1,0,0,406,39,1,0,0,0,407,408,5,27,0,0,408,409, + 5,2,0,0,409,410,3,234,117,0,410,41,1,0,0,0,411,412,5,117,0,0,412, + 413,5,2,0,0,413,418,5,156,0,0,414,415,5,117,0,0,415,416,5,2,0,0, + 416,418,3,234,117,0,417,411,1,0,0,0,417,414,1,0,0,0,418,43,1,0,0, + 0,419,420,5,118,0,0,420,421,5,2,0,0,421,429,3,78,39,0,422,423,5, + 118,0,0,423,424,5,2,0,0,424,429,5,153,0,0,425,426,5,118,0,0,426, + 427,5,2,0,0,427,429,5,155,0,0,428,419,1,0,0,0,428,422,1,0,0,0,428, + 425,1,0,0,0,429,45,1,0,0,0,430,431,5,115,0,0,431,432,5,2,0,0,432, + 437,5,156,0,0,433,434,5,115,0,0,434,435,5,2,0,0,435,437,3,234,117, + 0,436,430,1,0,0,0,436,433,1,0,0,0,437,47,1,0,0,0,438,439,5,116,0, + 0,439,440,5,2,0,0,440,448,3,78,39,0,441,442,5,116,0,0,442,443,5, + 2,0,0,443,448,5,153,0,0,444,445,5,116,0,0,445,446,5,2,0,0,446,448, + 5,155,0,0,447,438,1,0,0,0,447,441,1,0,0,0,447,444,1,0,0,0,448,49, + 1,0,0,0,449,450,5,72,0,0,450,451,5,2,0,0,451,456,5,156,0,0,452,453, + 5,72,0,0,453,454,5,2,0,0,454,456,5,158,0,0,455,449,1,0,0,0,455,452, + 1,0,0,0,456,51,1,0,0,0,457,458,5,71,0,0,458,459,5,2,0,0,459,464, + 3,78,39,0,460,461,5,71,0,0,461,462,5,2,0,0,462,464,3,234,117,0,463, + 457,1,0,0,0,463,460,1,0,0,0,464,53,1,0,0,0,465,466,5,74,0,0,466, + 467,5,2,0,0,467,472,5,156,0,0,468,469,5,74,0,0,469,470,5,2,0,0,470, + 472,3,234,117,0,471,465,1,0,0,0,471,468,1,0,0,0,472,55,1,0,0,0,473, + 474,5,73,0,0,474,475,5,2,0,0,475,480,3,78,39,0,476,477,5,73,0,0, + 477,478,5,2,0,0,478,480,3,234,117,0,479,473,1,0,0,0,479,476,1,0, + 0,0,480,57,1,0,0,0,481,482,5,93,0,0,482,483,5,2,0,0,483,488,3,116, + 58,0,484,485,5,93,0,0,485,486,5,2,0,0,486,488,5,156,0,0,487,481, + 1,0,0,0,487,484,1,0,0,0,488,59,1,0,0,0,489,490,5,94,0,0,490,491, + 5,2,0,0,491,499,5,152,0,0,492,493,5,94,0,0,493,494,5,2,0,0,494,499, + 3,78,39,0,495,496,5,94,0,0,496,497,5,2,0,0,497,499,3,234,117,0,498, + 489,1,0,0,0,498,492,1,0,0,0,498,495,1,0,0,0,499,61,1,0,0,0,500,501, + 5,89,0,0,501,502,5,2,0,0,502,507,5,156,0,0,503,504,5,89,0,0,504, + 505,5,2,0,0,505,507,5,158,0,0,506,500,1,0,0,0,506,503,1,0,0,0,507, + 63,1,0,0,0,508,509,5,88,0,0,509,510,5,2,0,0,510,515,3,78,39,0,511, + 512,5,88,0,0,512,513,5,2,0,0,513,515,5,153,0,0,514,508,1,0,0,0,514, + 511,1,0,0,0,515,65,1,0,0,0,516,517,5,97,0,0,517,518,5,2,0,0,518, + 519,3,80,40,0,519,67,1,0,0,0,520,521,5,98,0,0,521,522,5,2,0,0,522, + 523,3,80,40,0,523,69,1,0,0,0,524,525,5,75,0,0,525,526,5,2,0,0,526, + 531,5,156,0,0,527,528,5,75,0,0,528,529,5,2,0,0,529,531,5,158,0,0, + 530,524,1,0,0,0,530,527,1,0,0,0,531,71,1,0,0,0,532,533,5,76,0,0, + 533,534,5,2,0,0,534,539,3,78,39,0,535,536,5,76,0,0,536,537,5,2,0, + 0,537,539,5,153,0,0,538,532,1,0,0,0,538,535,1,0,0,0,539,73,1,0,0, + 0,540,541,5,77,0,0,541,542,5,2,0,0,542,547,5,156,0,0,543,544,5,77, + 0,0,544,545,5,2,0,0,545,547,5,158,0,0,546,540,1,0,0,0,546,543,1, + 0,0,0,547,75,1,0,0,0,548,549,5,78,0,0,549,550,5,2,0,0,550,555,3, + 78,39,0,551,552,5,78,0,0,552,553,5,2,0,0,553,555,5,153,0,0,554,548, + 1,0,0,0,554,551,1,0,0,0,555,77,1,0,0,0,556,557,5,154,0,0,557,79, + 1,0,0,0,558,559,5,5,0,0,559,564,3,82,41,0,560,561,5,1,0,0,561,563, + 3,82,41,0,562,560,1,0,0,0,563,566,1,0,0,0,564,562,1,0,0,0,564,565, 1,0,0,0,565,567,1,0,0,0,566,564,1,0,0,0,567,568,5,6,0,0,568,572, 1,0,0,0,569,570,5,5,0,0,570,572,5,6,0,0,571,558,1,0,0,0,571,569, 1,0,0,0,572,81,1,0,0,0,573,574,5,151,0,0,574,575,5,2,0,0,575,590, @@ -332,147 +332,148 @@ def serializedATN(): 0,798,777,1,0,0,0,798,787,1,0,0,0,799,127,1,0,0,0,800,806,3,134, 67,0,801,806,3,136,68,0,802,806,3,26,13,0,803,806,3,90,45,0,804, 806,3,8,4,0,805,800,1,0,0,0,805,801,1,0,0,0,805,802,1,0,0,0,805, - 803,1,0,0,0,805,804,1,0,0,0,806,129,1,0,0,0,807,811,3,132,66,0,808, - 811,3,26,13,0,809,811,3,90,45,0,810,807,1,0,0,0,810,808,1,0,0,0, - 810,809,1,0,0,0,811,131,1,0,0,0,812,813,3,220,110,0,813,826,5,2, - 0,0,814,827,3,126,63,0,815,816,5,3,0,0,816,821,3,126,63,0,817,818, - 5,1,0,0,818,820,3,126,63,0,819,817,1,0,0,0,820,823,1,0,0,0,821,819, - 1,0,0,0,821,822,1,0,0,0,822,824,1,0,0,0,823,821,1,0,0,0,824,825, - 5,4,0,0,825,827,1,0,0,0,826,814,1,0,0,0,826,815,1,0,0,0,827,133, - 1,0,0,0,828,829,5,26,0,0,829,830,5,2,0,0,830,838,5,153,0,0,831,832, - 5,26,0,0,832,833,5,2,0,0,833,838,3,78,39,0,834,835,5,26,0,0,835, - 836,5,2,0,0,836,838,5,152,0,0,837,828,1,0,0,0,837,831,1,0,0,0,837, - 834,1,0,0,0,838,135,1,0,0,0,839,840,5,25,0,0,840,841,5,2,0,0,841, - 854,7,1,0,0,842,843,5,25,0,0,843,844,5,2,0,0,844,854,5,156,0,0,845, - 846,3,218,109,0,846,847,5,2,0,0,847,848,3,78,39,0,848,854,1,0,0, - 0,849,850,3,218,109,0,850,851,5,2,0,0,851,852,3,232,116,0,852,854, - 1,0,0,0,853,839,1,0,0,0,853,842,1,0,0,0,853,845,1,0,0,0,853,849, - 1,0,0,0,854,137,1,0,0,0,855,856,5,28,0,0,856,857,5,2,0,0,857,858, - 5,3,0,0,858,863,3,2,1,0,859,860,5,1,0,0,860,862,3,2,1,0,861,859, - 1,0,0,0,862,865,1,0,0,0,863,861,1,0,0,0,863,864,1,0,0,0,864,866, - 1,0,0,0,865,863,1,0,0,0,866,867,5,4,0,0,867,139,1,0,0,0,868,869, - 5,85,0,0,869,870,5,2,0,0,870,871,5,5,0,0,871,876,3,142,71,0,872, - 873,5,1,0,0,873,875,3,142,71,0,874,872,1,0,0,0,875,878,1,0,0,0,876, - 874,1,0,0,0,876,877,1,0,0,0,877,879,1,0,0,0,878,876,1,0,0,0,879, - 880,5,6,0,0,880,141,1,0,0,0,881,886,3,144,72,0,882,886,3,6,3,0,883, - 886,3,16,8,0,884,886,3,8,4,0,885,881,1,0,0,0,885,882,1,0,0,0,885, - 883,1,0,0,0,885,884,1,0,0,0,886,143,1,0,0,0,887,888,5,79,0,0,888, - 889,5,2,0,0,889,890,5,5,0,0,890,895,3,146,73,0,891,892,5,1,0,0,892, - 894,3,146,73,0,893,891,1,0,0,0,894,897,1,0,0,0,895,893,1,0,0,0,895, - 896,1,0,0,0,896,898,1,0,0,0,897,895,1,0,0,0,898,899,5,6,0,0,899, - 145,1,0,0,0,900,903,3,148,74,0,901,903,3,152,76,0,902,900,1,0,0, - 0,902,901,1,0,0,0,903,147,1,0,0,0,904,905,5,80,0,0,905,906,5,2,0, - 0,906,907,3,150,75,0,907,149,1,0,0,0,908,909,7,3,0,0,909,151,1,0, - 0,0,910,911,5,83,0,0,911,912,5,2,0,0,912,913,3,154,77,0,913,153, - 1,0,0,0,914,915,5,84,0,0,915,155,1,0,0,0,916,917,5,86,0,0,917,918, - 5,2,0,0,918,919,5,5,0,0,919,924,3,158,79,0,920,921,5,1,0,0,921,923, - 3,158,79,0,922,920,1,0,0,0,923,926,1,0,0,0,924,922,1,0,0,0,924,925, - 1,0,0,0,925,927,1,0,0,0,926,924,1,0,0,0,927,928,5,6,0,0,928,157, - 1,0,0,0,929,934,3,6,3,0,930,934,3,16,8,0,931,934,3,8,4,0,932,934, - 3,144,72,0,933,929,1,0,0,0,933,930,1,0,0,0,933,931,1,0,0,0,933,932, - 1,0,0,0,934,159,1,0,0,0,935,936,5,87,0,0,936,937,5,2,0,0,937,938, - 3,80,40,0,938,161,1,0,0,0,939,940,5,100,0,0,940,941,5,2,0,0,941, - 942,5,5,0,0,942,947,3,164,82,0,943,944,5,1,0,0,944,946,3,164,82, - 0,945,943,1,0,0,0,946,949,1,0,0,0,947,945,1,0,0,0,947,948,1,0,0, - 0,948,950,1,0,0,0,949,947,1,0,0,0,950,951,5,6,0,0,951,163,1,0,0, - 0,952,957,3,28,14,0,953,957,3,166,83,0,954,957,3,66,33,0,955,957, - 3,106,53,0,956,952,1,0,0,0,956,953,1,0,0,0,956,954,1,0,0,0,956,955, - 1,0,0,0,957,165,1,0,0,0,958,959,5,101,0,0,959,960,5,2,0,0,960,961, - 5,5,0,0,961,966,3,168,84,0,962,963,5,1,0,0,963,965,3,168,84,0,964, - 962,1,0,0,0,965,968,1,0,0,0,966,964,1,0,0,0,966,967,1,0,0,0,967, - 969,1,0,0,0,968,966,1,0,0,0,969,970,5,6,0,0,970,167,1,0,0,0,971, - 977,3,170,85,0,972,977,3,172,86,0,973,977,3,174,87,0,974,977,3,176, - 88,0,975,977,3,178,89,0,976,971,1,0,0,0,976,972,1,0,0,0,976,973, - 1,0,0,0,976,974,1,0,0,0,976,975,1,0,0,0,977,169,1,0,0,0,978,979, - 5,102,0,0,979,980,5,2,0,0,980,981,3,234,117,0,981,171,1,0,0,0,982, - 983,5,103,0,0,983,984,5,2,0,0,984,985,3,234,117,0,985,173,1,0,0, - 0,986,987,5,104,0,0,987,988,5,2,0,0,988,989,5,3,0,0,989,994,3,234, - 117,0,990,991,5,1,0,0,991,993,3,234,117,0,992,990,1,0,0,0,993,996, - 1,0,0,0,994,992,1,0,0,0,994,995,1,0,0,0,995,997,1,0,0,0,996,994, - 1,0,0,0,997,998,5,4,0,0,998,175,1,0,0,0,999,1000,5,105,0,0,1000, - 1001,5,2,0,0,1001,1006,5,156,0,0,1002,1003,5,105,0,0,1003,1004,5, - 2,0,0,1004,1006,5,158,0,0,1005,999,1,0,0,0,1005,1002,1,0,0,0,1006, - 177,1,0,0,0,1007,1008,5,106,0,0,1008,1009,5,2,0,0,1009,1014,3,78, - 39,0,1010,1011,5,106,0,0,1011,1012,5,2,0,0,1012,1014,5,153,0,0,1013, - 1007,1,0,0,0,1013,1010,1,0,0,0,1014,179,1,0,0,0,1015,1016,5,107, - 0,0,1016,1017,5,2,0,0,1017,1022,5,156,0,0,1018,1019,5,107,0,0,1019, - 1020,5,2,0,0,1020,1022,5,158,0,0,1021,1015,1,0,0,0,1021,1018,1,0, - 0,0,1022,181,1,0,0,0,1023,1024,5,108,0,0,1024,1025,5,2,0,0,1025, - 1030,3,78,39,0,1026,1027,5,108,0,0,1027,1028,5,2,0,0,1028,1030,5, - 153,0,0,1029,1023,1,0,0,0,1029,1026,1,0,0,0,1030,183,1,0,0,0,1031, - 1032,5,109,0,0,1032,1033,5,2,0,0,1033,1038,5,156,0,0,1034,1035,5, - 109,0,0,1035,1036,5,2,0,0,1036,1038,5,159,0,0,1037,1031,1,0,0,0, - 1037,1034,1,0,0,0,1038,185,1,0,0,0,1039,1040,5,110,0,0,1040,1041, - 5,2,0,0,1041,1046,3,78,39,0,1042,1043,5,110,0,0,1043,1044,5,2,0, - 0,1044,1046,5,153,0,0,1045,1039,1,0,0,0,1045,1042,1,0,0,0,1046,187, - 1,0,0,0,1047,1048,5,111,0,0,1048,1049,5,2,0,0,1049,1050,3,234,117, - 0,1050,189,1,0,0,0,1051,1052,5,112,0,0,1052,1053,5,2,0,0,1053,1054, - 5,5,0,0,1054,1059,3,192,96,0,1055,1056,5,1,0,0,1056,1058,3,192,96, - 0,1057,1055,1,0,0,0,1058,1061,1,0,0,0,1059,1057,1,0,0,0,1059,1060, - 1,0,0,0,1060,1062,1,0,0,0,1061,1059,1,0,0,0,1062,1063,5,6,0,0,1063, - 191,1,0,0,0,1064,1067,3,28,14,0,1065,1067,3,66,33,0,1066,1064,1, - 0,0,0,1066,1065,1,0,0,0,1067,193,1,0,0,0,1068,1069,5,119,0,0,1069, - 1070,5,2,0,0,1070,1079,5,3,0,0,1071,1076,3,196,98,0,1072,1073,5, - 1,0,0,1073,1075,3,196,98,0,1074,1072,1,0,0,0,1075,1078,1,0,0,0,1076, - 1074,1,0,0,0,1076,1077,1,0,0,0,1077,1080,1,0,0,0,1078,1076,1,0,0, - 0,1079,1071,1,0,0,0,1079,1080,1,0,0,0,1080,1081,1,0,0,0,1081,1082, - 5,4,0,0,1082,195,1,0,0,0,1083,1084,5,5,0,0,1084,1089,3,198,99,0, - 1085,1086,5,1,0,0,1086,1088,3,198,99,0,1087,1085,1,0,0,0,1088,1091, - 1,0,0,0,1089,1087,1,0,0,0,1089,1090,1,0,0,0,1090,1092,1,0,0,0,1091, - 1089,1,0,0,0,1092,1093,5,6,0,0,1093,197,1,0,0,0,1094,1102,3,200, - 100,0,1095,1102,3,202,101,0,1096,1102,3,204,102,0,1097,1102,3,206, - 103,0,1098,1102,3,208,104,0,1099,1102,3,210,105,0,1100,1102,3,8, - 4,0,1101,1094,1,0,0,0,1101,1095,1,0,0,0,1101,1096,1,0,0,0,1101,1097, - 1,0,0,0,1101,1098,1,0,0,0,1101,1099,1,0,0,0,1101,1100,1,0,0,0,1102, - 199,1,0,0,0,1103,1104,5,120,0,0,1104,1105,5,2,0,0,1105,1106,5,3, - 0,0,1106,1111,3,224,112,0,1107,1108,5,1,0,0,1108,1110,3,224,112, - 0,1109,1107,1,0,0,0,1110,1113,1,0,0,0,1111,1109,1,0,0,0,1111,1112, - 1,0,0,0,1112,1114,1,0,0,0,1113,1111,1,0,0,0,1114,1115,5,4,0,0,1115, - 201,1,0,0,0,1116,1117,5,121,0,0,1117,1118,5,2,0,0,1118,1119,5,158, - 0,0,1119,203,1,0,0,0,1120,1121,5,122,0,0,1121,1122,5,2,0,0,1122, - 1123,5,158,0,0,1123,205,1,0,0,0,1124,1125,5,123,0,0,1125,1126,5, - 2,0,0,1126,1127,7,4,0,0,1127,207,1,0,0,0,1128,1129,5,124,0,0,1129, - 1130,5,2,0,0,1130,1131,5,158,0,0,1131,209,1,0,0,0,1132,1133,5,125, - 0,0,1133,1134,5,2,0,0,1134,1135,7,5,0,0,1135,211,1,0,0,0,1136,1137, - 5,128,0,0,1137,1138,5,2,0,0,1138,1147,5,3,0,0,1139,1144,3,214,107, - 0,1140,1141,5,1,0,0,1141,1143,3,214,107,0,1142,1140,1,0,0,0,1143, - 1146,1,0,0,0,1144,1142,1,0,0,0,1144,1145,1,0,0,0,1145,1148,1,0,0, - 0,1146,1144,1,0,0,0,1147,1139,1,0,0,0,1147,1148,1,0,0,0,1148,1149, - 1,0,0,0,1149,1150,5,4,0,0,1150,213,1,0,0,0,1151,1152,5,5,0,0,1152, - 1157,3,216,108,0,1153,1154,5,1,0,0,1154,1156,3,216,108,0,1155,1153, - 1,0,0,0,1156,1159,1,0,0,0,1157,1155,1,0,0,0,1157,1158,1,0,0,0,1158, - 1160,1,0,0,0,1159,1157,1,0,0,0,1160,1161,5,6,0,0,1161,215,1,0,0, - 0,1162,1169,3,200,100,0,1163,1169,3,34,17,0,1164,1169,3,26,13,0, - 1165,1169,3,90,45,0,1166,1169,3,108,54,0,1167,1169,3,8,4,0,1168, - 1162,1,0,0,0,1168,1163,1,0,0,0,1168,1164,1,0,0,0,1168,1165,1,0,0, - 0,1168,1166,1,0,0,0,1168,1167,1,0,0,0,1169,217,1,0,0,0,1170,1171, - 7,6,0,0,1171,219,1,0,0,0,1172,1173,7,7,0,0,1173,221,1,0,0,0,1174, - 1175,7,8,0,0,1175,223,1,0,0,0,1176,1179,3,222,111,0,1177,1179,3, - 234,117,0,1178,1176,1,0,0,0,1178,1177,1,0,0,0,1179,225,1,0,0,0,1180, - 1181,5,5,0,0,1181,1186,3,228,114,0,1182,1183,5,1,0,0,1183,1185,3, - 228,114,0,1184,1182,1,0,0,0,1185,1188,1,0,0,0,1186,1184,1,0,0,0, - 1186,1187,1,0,0,0,1187,1189,1,0,0,0,1188,1186,1,0,0,0,1189,1190, - 5,6,0,0,1190,1194,1,0,0,0,1191,1192,5,5,0,0,1192,1194,5,6,0,0,1193, - 1180,1,0,0,0,1193,1191,1,0,0,0,1194,227,1,0,0,0,1195,1196,3,234, - 117,0,1196,1197,5,2,0,0,1197,1198,3,232,116,0,1198,229,1,0,0,0,1199, - 1200,5,3,0,0,1200,1205,3,232,116,0,1201,1202,5,1,0,0,1202,1204,3, - 232,116,0,1203,1201,1,0,0,0,1204,1207,1,0,0,0,1205,1203,1,0,0,0, - 1205,1206,1,0,0,0,1206,1208,1,0,0,0,1207,1205,1,0,0,0,1208,1209, - 5,4,0,0,1209,1213,1,0,0,0,1210,1211,5,3,0,0,1211,1213,5,4,0,0,1212, - 1199,1,0,0,0,1212,1210,1,0,0,0,1213,231,1,0,0,0,1214,1224,5,159, - 0,0,1215,1224,5,158,0,0,1216,1224,5,7,0,0,1217,1224,5,8,0,0,1218, - 1224,5,9,0,0,1219,1224,3,228,114,0,1220,1224,3,230,115,0,1221,1224, - 3,226,113,0,1222,1224,3,234,117,0,1223,1214,1,0,0,0,1223,1215,1, - 0,0,0,1223,1216,1,0,0,0,1223,1217,1,0,0,0,1223,1218,1,0,0,0,1223, - 1219,1,0,0,0,1223,1220,1,0,0,0,1223,1221,1,0,0,0,1223,1222,1,0,0, - 0,1224,233,1,0,0,0,1225,1226,7,9,0,0,1226,235,1,0,0,0,94,245,256, + 803,1,0,0,0,805,804,1,0,0,0,806,129,1,0,0,0,807,812,3,132,66,0,808, + 812,3,26,13,0,809,812,3,90,45,0,810,812,3,8,4,0,811,807,1,0,0,0, + 811,808,1,0,0,0,811,809,1,0,0,0,811,810,1,0,0,0,812,131,1,0,0,0, + 813,814,3,220,110,0,814,827,5,2,0,0,815,828,3,126,63,0,816,817,5, + 3,0,0,817,822,3,126,63,0,818,819,5,1,0,0,819,821,3,126,63,0,820, + 818,1,0,0,0,821,824,1,0,0,0,822,820,1,0,0,0,822,823,1,0,0,0,823, + 825,1,0,0,0,824,822,1,0,0,0,825,826,5,4,0,0,826,828,1,0,0,0,827, + 815,1,0,0,0,827,816,1,0,0,0,828,133,1,0,0,0,829,830,5,26,0,0,830, + 831,5,2,0,0,831,839,5,153,0,0,832,833,5,26,0,0,833,834,5,2,0,0,834, + 839,3,78,39,0,835,836,5,26,0,0,836,837,5,2,0,0,837,839,5,152,0,0, + 838,829,1,0,0,0,838,832,1,0,0,0,838,835,1,0,0,0,839,135,1,0,0,0, + 840,841,5,25,0,0,841,842,5,2,0,0,842,855,7,1,0,0,843,844,5,25,0, + 0,844,845,5,2,0,0,845,855,5,156,0,0,846,847,3,218,109,0,847,848, + 5,2,0,0,848,849,3,78,39,0,849,855,1,0,0,0,850,851,3,218,109,0,851, + 852,5,2,0,0,852,853,3,232,116,0,853,855,1,0,0,0,854,840,1,0,0,0, + 854,843,1,0,0,0,854,846,1,0,0,0,854,850,1,0,0,0,855,137,1,0,0,0, + 856,857,5,28,0,0,857,858,5,2,0,0,858,859,5,3,0,0,859,864,3,2,1,0, + 860,861,5,1,0,0,861,863,3,2,1,0,862,860,1,0,0,0,863,866,1,0,0,0, + 864,862,1,0,0,0,864,865,1,0,0,0,865,867,1,0,0,0,866,864,1,0,0,0, + 867,868,5,4,0,0,868,139,1,0,0,0,869,870,5,85,0,0,870,871,5,2,0,0, + 871,872,5,5,0,0,872,877,3,142,71,0,873,874,5,1,0,0,874,876,3,142, + 71,0,875,873,1,0,0,0,876,879,1,0,0,0,877,875,1,0,0,0,877,878,1,0, + 0,0,878,880,1,0,0,0,879,877,1,0,0,0,880,881,5,6,0,0,881,141,1,0, + 0,0,882,887,3,144,72,0,883,887,3,6,3,0,884,887,3,16,8,0,885,887, + 3,8,4,0,886,882,1,0,0,0,886,883,1,0,0,0,886,884,1,0,0,0,886,885, + 1,0,0,0,887,143,1,0,0,0,888,889,5,79,0,0,889,890,5,2,0,0,890,891, + 5,5,0,0,891,896,3,146,73,0,892,893,5,1,0,0,893,895,3,146,73,0,894, + 892,1,0,0,0,895,898,1,0,0,0,896,894,1,0,0,0,896,897,1,0,0,0,897, + 899,1,0,0,0,898,896,1,0,0,0,899,900,5,6,0,0,900,145,1,0,0,0,901, + 904,3,148,74,0,902,904,3,152,76,0,903,901,1,0,0,0,903,902,1,0,0, + 0,904,147,1,0,0,0,905,906,5,80,0,0,906,907,5,2,0,0,907,908,3,150, + 75,0,908,149,1,0,0,0,909,910,7,3,0,0,910,151,1,0,0,0,911,912,5,83, + 0,0,912,913,5,2,0,0,913,914,3,154,77,0,914,153,1,0,0,0,915,916,5, + 84,0,0,916,155,1,0,0,0,917,918,5,86,0,0,918,919,5,2,0,0,919,920, + 5,5,0,0,920,925,3,158,79,0,921,922,5,1,0,0,922,924,3,158,79,0,923, + 921,1,0,0,0,924,927,1,0,0,0,925,923,1,0,0,0,925,926,1,0,0,0,926, + 928,1,0,0,0,927,925,1,0,0,0,928,929,5,6,0,0,929,157,1,0,0,0,930, + 935,3,6,3,0,931,935,3,16,8,0,932,935,3,8,4,0,933,935,3,144,72,0, + 934,930,1,0,0,0,934,931,1,0,0,0,934,932,1,0,0,0,934,933,1,0,0,0, + 935,159,1,0,0,0,936,937,5,87,0,0,937,938,5,2,0,0,938,939,3,80,40, + 0,939,161,1,0,0,0,940,941,5,100,0,0,941,942,5,2,0,0,942,943,5,5, + 0,0,943,948,3,164,82,0,944,945,5,1,0,0,945,947,3,164,82,0,946,944, + 1,0,0,0,947,950,1,0,0,0,948,946,1,0,0,0,948,949,1,0,0,0,949,951, + 1,0,0,0,950,948,1,0,0,0,951,952,5,6,0,0,952,163,1,0,0,0,953,958, + 3,28,14,0,954,958,3,166,83,0,955,958,3,66,33,0,956,958,3,106,53, + 0,957,953,1,0,0,0,957,954,1,0,0,0,957,955,1,0,0,0,957,956,1,0,0, + 0,958,165,1,0,0,0,959,960,5,101,0,0,960,961,5,2,0,0,961,962,5,5, + 0,0,962,967,3,168,84,0,963,964,5,1,0,0,964,966,3,168,84,0,965,963, + 1,0,0,0,966,969,1,0,0,0,967,965,1,0,0,0,967,968,1,0,0,0,968,970, + 1,0,0,0,969,967,1,0,0,0,970,971,5,6,0,0,971,167,1,0,0,0,972,978, + 3,170,85,0,973,978,3,172,86,0,974,978,3,174,87,0,975,978,3,176,88, + 0,976,978,3,178,89,0,977,972,1,0,0,0,977,973,1,0,0,0,977,974,1,0, + 0,0,977,975,1,0,0,0,977,976,1,0,0,0,978,169,1,0,0,0,979,980,5,102, + 0,0,980,981,5,2,0,0,981,982,3,234,117,0,982,171,1,0,0,0,983,984, + 5,103,0,0,984,985,5,2,0,0,985,986,3,234,117,0,986,173,1,0,0,0,987, + 988,5,104,0,0,988,989,5,2,0,0,989,990,5,3,0,0,990,995,3,234,117, + 0,991,992,5,1,0,0,992,994,3,234,117,0,993,991,1,0,0,0,994,997,1, + 0,0,0,995,993,1,0,0,0,995,996,1,0,0,0,996,998,1,0,0,0,997,995,1, + 0,0,0,998,999,5,4,0,0,999,175,1,0,0,0,1000,1001,5,105,0,0,1001,1002, + 5,2,0,0,1002,1007,5,156,0,0,1003,1004,5,105,0,0,1004,1005,5,2,0, + 0,1005,1007,5,158,0,0,1006,1000,1,0,0,0,1006,1003,1,0,0,0,1007,177, + 1,0,0,0,1008,1009,5,106,0,0,1009,1010,5,2,0,0,1010,1015,3,78,39, + 0,1011,1012,5,106,0,0,1012,1013,5,2,0,0,1013,1015,5,153,0,0,1014, + 1008,1,0,0,0,1014,1011,1,0,0,0,1015,179,1,0,0,0,1016,1017,5,107, + 0,0,1017,1018,5,2,0,0,1018,1023,5,156,0,0,1019,1020,5,107,0,0,1020, + 1021,5,2,0,0,1021,1023,5,158,0,0,1022,1016,1,0,0,0,1022,1019,1,0, + 0,0,1023,181,1,0,0,0,1024,1025,5,108,0,0,1025,1026,5,2,0,0,1026, + 1031,3,78,39,0,1027,1028,5,108,0,0,1028,1029,5,2,0,0,1029,1031,5, + 153,0,0,1030,1024,1,0,0,0,1030,1027,1,0,0,0,1031,183,1,0,0,0,1032, + 1033,5,109,0,0,1033,1034,5,2,0,0,1034,1039,5,156,0,0,1035,1036,5, + 109,0,0,1036,1037,5,2,0,0,1037,1039,5,159,0,0,1038,1032,1,0,0,0, + 1038,1035,1,0,0,0,1039,185,1,0,0,0,1040,1041,5,110,0,0,1041,1042, + 5,2,0,0,1042,1047,3,78,39,0,1043,1044,5,110,0,0,1044,1045,5,2,0, + 0,1045,1047,5,153,0,0,1046,1040,1,0,0,0,1046,1043,1,0,0,0,1047,187, + 1,0,0,0,1048,1049,5,111,0,0,1049,1050,5,2,0,0,1050,1051,3,234,117, + 0,1051,189,1,0,0,0,1052,1053,5,112,0,0,1053,1054,5,2,0,0,1054,1055, + 5,5,0,0,1055,1060,3,192,96,0,1056,1057,5,1,0,0,1057,1059,3,192,96, + 0,1058,1056,1,0,0,0,1059,1062,1,0,0,0,1060,1058,1,0,0,0,1060,1061, + 1,0,0,0,1061,1063,1,0,0,0,1062,1060,1,0,0,0,1063,1064,5,6,0,0,1064, + 191,1,0,0,0,1065,1068,3,28,14,0,1066,1068,3,66,33,0,1067,1065,1, + 0,0,0,1067,1066,1,0,0,0,1068,193,1,0,0,0,1069,1070,5,119,0,0,1070, + 1071,5,2,0,0,1071,1080,5,3,0,0,1072,1077,3,196,98,0,1073,1074,5, + 1,0,0,1074,1076,3,196,98,0,1075,1073,1,0,0,0,1076,1079,1,0,0,0,1077, + 1075,1,0,0,0,1077,1078,1,0,0,0,1078,1081,1,0,0,0,1079,1077,1,0,0, + 0,1080,1072,1,0,0,0,1080,1081,1,0,0,0,1081,1082,1,0,0,0,1082,1083, + 5,4,0,0,1083,195,1,0,0,0,1084,1085,5,5,0,0,1085,1090,3,198,99,0, + 1086,1087,5,1,0,0,1087,1089,3,198,99,0,1088,1086,1,0,0,0,1089,1092, + 1,0,0,0,1090,1088,1,0,0,0,1090,1091,1,0,0,0,1091,1093,1,0,0,0,1092, + 1090,1,0,0,0,1093,1094,5,6,0,0,1094,197,1,0,0,0,1095,1103,3,200, + 100,0,1096,1103,3,202,101,0,1097,1103,3,204,102,0,1098,1103,3,206, + 103,0,1099,1103,3,208,104,0,1100,1103,3,210,105,0,1101,1103,3,8, + 4,0,1102,1095,1,0,0,0,1102,1096,1,0,0,0,1102,1097,1,0,0,0,1102,1098, + 1,0,0,0,1102,1099,1,0,0,0,1102,1100,1,0,0,0,1102,1101,1,0,0,0,1103, + 199,1,0,0,0,1104,1105,5,120,0,0,1105,1106,5,2,0,0,1106,1107,5,3, + 0,0,1107,1112,3,224,112,0,1108,1109,5,1,0,0,1109,1111,3,224,112, + 0,1110,1108,1,0,0,0,1111,1114,1,0,0,0,1112,1110,1,0,0,0,1112,1113, + 1,0,0,0,1113,1115,1,0,0,0,1114,1112,1,0,0,0,1115,1116,5,4,0,0,1116, + 201,1,0,0,0,1117,1118,5,121,0,0,1118,1119,5,2,0,0,1119,1120,5,158, + 0,0,1120,203,1,0,0,0,1121,1122,5,122,0,0,1122,1123,5,2,0,0,1123, + 1124,5,158,0,0,1124,205,1,0,0,0,1125,1126,5,123,0,0,1126,1127,5, + 2,0,0,1127,1128,7,4,0,0,1128,207,1,0,0,0,1129,1130,5,124,0,0,1130, + 1131,5,2,0,0,1131,1132,5,158,0,0,1132,209,1,0,0,0,1133,1134,5,125, + 0,0,1134,1135,5,2,0,0,1135,1136,7,5,0,0,1136,211,1,0,0,0,1137,1138, + 5,128,0,0,1138,1139,5,2,0,0,1139,1148,5,3,0,0,1140,1145,3,214,107, + 0,1141,1142,5,1,0,0,1142,1144,3,214,107,0,1143,1141,1,0,0,0,1144, + 1147,1,0,0,0,1145,1143,1,0,0,0,1145,1146,1,0,0,0,1146,1149,1,0,0, + 0,1147,1145,1,0,0,0,1148,1140,1,0,0,0,1148,1149,1,0,0,0,1149,1150, + 1,0,0,0,1150,1151,5,4,0,0,1151,213,1,0,0,0,1152,1153,5,5,0,0,1153, + 1158,3,216,108,0,1154,1155,5,1,0,0,1155,1157,3,216,108,0,1156,1154, + 1,0,0,0,1157,1160,1,0,0,0,1158,1156,1,0,0,0,1158,1159,1,0,0,0,1159, + 1161,1,0,0,0,1160,1158,1,0,0,0,1161,1162,5,6,0,0,1162,215,1,0,0, + 0,1163,1170,3,200,100,0,1164,1170,3,34,17,0,1165,1170,3,26,13,0, + 1166,1170,3,90,45,0,1167,1170,3,108,54,0,1168,1170,3,8,4,0,1169, + 1163,1,0,0,0,1169,1164,1,0,0,0,1169,1165,1,0,0,0,1169,1166,1,0,0, + 0,1169,1167,1,0,0,0,1169,1168,1,0,0,0,1170,217,1,0,0,0,1171,1172, + 7,6,0,0,1172,219,1,0,0,0,1173,1174,7,7,0,0,1174,221,1,0,0,0,1175, + 1176,7,8,0,0,1176,223,1,0,0,0,1177,1180,3,222,111,0,1178,1180,3, + 234,117,0,1179,1177,1,0,0,0,1179,1178,1,0,0,0,1180,225,1,0,0,0,1181, + 1182,5,5,0,0,1182,1187,3,228,114,0,1183,1184,5,1,0,0,1184,1186,3, + 228,114,0,1185,1183,1,0,0,0,1186,1189,1,0,0,0,1187,1185,1,0,0,0, + 1187,1188,1,0,0,0,1188,1190,1,0,0,0,1189,1187,1,0,0,0,1190,1191, + 5,6,0,0,1191,1195,1,0,0,0,1192,1193,5,5,0,0,1193,1195,5,6,0,0,1194, + 1181,1,0,0,0,1194,1192,1,0,0,0,1195,227,1,0,0,0,1196,1197,3,234, + 117,0,1197,1198,5,2,0,0,1198,1199,3,232,116,0,1199,229,1,0,0,0,1200, + 1201,5,3,0,0,1201,1206,3,232,116,0,1202,1203,5,1,0,0,1203,1205,3, + 232,116,0,1204,1202,1,0,0,0,1205,1208,1,0,0,0,1206,1204,1,0,0,0, + 1206,1207,1,0,0,0,1207,1209,1,0,0,0,1208,1206,1,0,0,0,1209,1210, + 5,4,0,0,1210,1214,1,0,0,0,1211,1212,5,3,0,0,1212,1214,5,4,0,0,1213, + 1200,1,0,0,0,1213,1211,1,0,0,0,1214,231,1,0,0,0,1215,1225,5,159, + 0,0,1216,1225,5,158,0,0,1217,1225,5,7,0,0,1218,1225,5,8,0,0,1219, + 1225,5,9,0,0,1220,1225,3,228,114,0,1221,1225,3,230,115,0,1222,1225, + 3,226,113,0,1223,1225,3,234,117,0,1224,1215,1,0,0,0,1224,1216,1, + 0,0,0,1224,1217,1,0,0,0,1224,1218,1,0,0,0,1224,1219,1,0,0,0,1224, + 1220,1,0,0,0,1224,1221,1,0,0,0,1224,1222,1,0,0,0,1224,1223,1,0,0, + 0,1225,233,1,0,0,0,1226,1227,7,9,0,0,1227,235,1,0,0,0,94,245,256, 321,331,348,375,377,387,399,401,417,428,436,447,455,463,471,479, 487,498,506,514,530,538,546,554,564,571,589,597,604,609,616,630, 635,647,652,669,674,684,689,697,705,719,724,733,743,748,756,772, - 783,793,798,805,810,821,826,837,853,863,876,885,895,902,924,933, - 947,956,966,976,994,1005,1013,1021,1029,1037,1045,1059,1066,1076, - 1079,1089,1101,1111,1144,1147,1157,1168,1178,1186,1193,1205,1212, - 1223 + 783,793,798,805,811,822,827,838,854,864,877,886,896,903,925,934, + 948,957,967,977,995,1006,1014,1022,1030,1038,1046,1060,1067,1077, + 1080,1090,1102,1112,1145,1148,1158,1169,1179,1187,1194,1206,1213, + 1224 ] class ASLParser ( Parser ): @@ -7870,6 +7871,10 @@ def assign_decl(self): return self.getTypedRuleContext(ASLParser.Assign_declContext,0) + def comment_decl(self): + return self.getTypedRuleContext(ASLParser.Comment_declContext,0) + + def getRuleIndex(self): return ASLParser.RULE_comparison_composite_stmt @@ -7895,7 +7900,7 @@ def comparison_composite_stmt(self): localctx = ASLParser.Comparison_composite_stmtContext(self, self._ctx, self.state) self.enterRule(localctx, 130, self.RULE_comparison_composite_stmt) try: - self.state = 810 + self.state = 811 self._errHandler.sync(self) token = self._input.LA(1) if token in [29, 38, 49]: @@ -7913,6 +7918,11 @@ def comparison_composite_stmt(self): self.state = 809 self.assign_decl() pass + elif token in [10]: + self.enterOuterAlt(localctx, 4) + self.state = 810 + self.comment_decl() + pass else: raise NoViableAltException(self) @@ -7985,35 +7995,35 @@ def comparison_composite(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 812 - self.choice_operator() self.state = 813 + self.choice_operator() + self.state = 814 self.match(ASLParser.COLON) - self.state = 826 + self.state = 827 self._errHandler.sync(self) token = self._input.LA(1) if token in [5]: - self.state = 814 + self.state = 815 self.choice_rule() pass elif token in [3]: - self.state = 815 - self.match(ASLParser.LBRACK) self.state = 816 + self.match(ASLParser.LBRACK) + self.state = 817 self.choice_rule() - self.state = 821 + self.state = 822 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 817 - self.match(ASLParser.COMMA) self.state = 818 + self.match(ASLParser.COMMA) + self.state = 819 self.choice_rule() - self.state = 823 + self.state = 824 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 824 + self.state = 825 self.match(ASLParser.RBRACK) pass else: @@ -8136,39 +8146,39 @@ def variable_decl(self): localctx = ASLParser.Variable_declContext(self, self._ctx, self.state) self.enterRule(localctx, 134, self.RULE_variable_decl) try: - self.state = 837 + self.state = 838 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,57,self._ctx) if la_ == 1: localctx = ASLParser.Variable_decl_pathContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 828 - self.match(ASLParser.VARIABLE) self.state = 829 - self.match(ASLParser.COLON) + self.match(ASLParser.VARIABLE) self.state = 830 + self.match(ASLParser.COLON) + self.state = 831 self.match(ASLParser.STRINGPATH) pass elif la_ == 2: localctx = ASLParser.Variable_decl_varContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 831 - self.match(ASLParser.VARIABLE) self.state = 832 - self.match(ASLParser.COLON) + self.match(ASLParser.VARIABLE) self.state = 833 + self.match(ASLParser.COLON) + self.state = 834 self.variable_sample() pass elif la_ == 3: localctx = ASLParser.Variable_decl_path_context_objectContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 834 - self.match(ASLParser.VARIABLE) self.state = 835 - self.match(ASLParser.COLON) + self.match(ASLParser.VARIABLE) self.state = 836 + self.match(ASLParser.COLON) + self.state = 837 self.match(ASLParser.STRINGPATHCONTEXTOBJ) pass @@ -8324,17 +8334,17 @@ def comparison_func(self): self.enterRule(localctx, 136, self.RULE_comparison_func) self._la = 0 # Token type try: - self.state = 853 + self.state = 854 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,58,self._ctx) if la_ == 1: localctx = ASLParser.Condition_litContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 839 - self.match(ASLParser.CONDITION) self.state = 840 - self.match(ASLParser.COLON) + self.match(ASLParser.CONDITION) self.state = 841 + self.match(ASLParser.COLON) + self.state = 842 _la = self._input.LA(1) if not(_la==7 or _la==8): self._errHandler.recoverInline(self) @@ -8346,33 +8356,33 @@ def comparison_func(self): elif la_ == 2: localctx = ASLParser.Condition_exprContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 842 - self.match(ASLParser.CONDITION) self.state = 843 - self.match(ASLParser.COLON) + self.match(ASLParser.CONDITION) self.state = 844 + self.match(ASLParser.COLON) + self.state = 845 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 3: localctx = ASLParser.Comparison_func_varContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 845 - self.comparison_op() self.state = 846 - self.match(ASLParser.COLON) + self.comparison_op() self.state = 847 + self.match(ASLParser.COLON) + self.state = 848 self.variable_sample() pass elif la_ == 4: localctx = ASLParser.Comparison_func_valueContext(self, localctx) self.enterOuterAlt(localctx, 4) - self.state = 849 - self.comparison_op() self.state = 850 - self.match(ASLParser.COLON) + self.comparison_op() self.state = 851 + self.match(ASLParser.COLON) + self.state = 852 self.json_value_decl() pass @@ -8445,27 +8455,27 @@ def branches_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 855 - self.match(ASLParser.BRANCHES) self.state = 856 - self.match(ASLParser.COLON) + self.match(ASLParser.BRANCHES) self.state = 857 - self.match(ASLParser.LBRACK) + self.match(ASLParser.COLON) self.state = 858 + self.match(ASLParser.LBRACK) + self.state = 859 self.program_decl() - self.state = 863 + self.state = 864 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 859 - self.match(ASLParser.COMMA) self.state = 860 + self.match(ASLParser.COMMA) + self.state = 861 self.program_decl() - self.state = 865 + self.state = 866 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 866 + self.state = 867 self.match(ASLParser.RBRACK) except RecognitionException as re: localctx.exception = re @@ -8535,27 +8545,27 @@ def item_processor_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 868 - self.match(ASLParser.ITEMPROCESSOR) self.state = 869 - self.match(ASLParser.COLON) + self.match(ASLParser.ITEMPROCESSOR) self.state = 870 - self.match(ASLParser.LBRACE) + self.match(ASLParser.COLON) self.state = 871 + self.match(ASLParser.LBRACE) + self.state = 872 self.item_processor_item() - self.state = 876 + self.state = 877 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 872 - self.match(ASLParser.COMMA) self.state = 873 + self.match(ASLParser.COMMA) + self.state = 874 self.item_processor_item() - self.state = 878 + self.state = 879 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 879 + self.state = 880 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -8614,27 +8624,27 @@ def item_processor_item(self): localctx = ASLParser.Item_processor_itemContext(self, self._ctx, self.state) self.enterRule(localctx, 142, self.RULE_item_processor_item) try: - self.state = 885 + self.state = 886 self._errHandler.sync(self) token = self._input.LA(1) if token in [79]: self.enterOuterAlt(localctx, 1) - self.state = 881 + self.state = 882 self.processor_config_decl() pass elif token in [12]: self.enterOuterAlt(localctx, 2) - self.state = 882 + self.state = 883 self.startat_decl() pass elif token in [11]: self.enterOuterAlt(localctx, 3) - self.state = 883 + self.state = 884 self.states_decl() pass elif token in [10]: self.enterOuterAlt(localctx, 4) - self.state = 884 + self.state = 885 self.comment_decl() pass else: @@ -8708,27 +8718,27 @@ def processor_config_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 887 - self.match(ASLParser.PROCESSORCONFIG) self.state = 888 - self.match(ASLParser.COLON) + self.match(ASLParser.PROCESSORCONFIG) self.state = 889 - self.match(ASLParser.LBRACE) + self.match(ASLParser.COLON) self.state = 890 + self.match(ASLParser.LBRACE) + self.state = 891 self.processor_config_field() - self.state = 895 + self.state = 896 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 891 - self.match(ASLParser.COMMA) self.state = 892 + self.match(ASLParser.COMMA) + self.state = 893 self.processor_config_field() - self.state = 897 + self.state = 898 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 898 + self.state = 899 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -8779,17 +8789,17 @@ def processor_config_field(self): localctx = ASLParser.Processor_config_fieldContext(self, self._ctx, self.state) self.enterRule(localctx, 146, self.RULE_processor_config_field) try: - self.state = 902 + self.state = 903 self._errHandler.sync(self) token = self._input.LA(1) if token in [80]: self.enterOuterAlt(localctx, 1) - self.state = 900 + self.state = 901 self.mode_decl() pass elif token in [83]: self.enterOuterAlt(localctx, 2) - self.state = 901 + self.state = 902 self.execution_decl() pass else: @@ -8847,11 +8857,11 @@ def mode_decl(self): self.enterRule(localctx, 148, self.RULE_mode_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 904 - self.match(ASLParser.MODE) self.state = 905 - self.match(ASLParser.COLON) + self.match(ASLParser.MODE) self.state = 906 + self.match(ASLParser.COLON) + self.state = 907 self.mode_type() except RecognitionException as re: localctx.exception = re @@ -8902,7 +8912,7 @@ def mode_type(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 908 + self.state = 909 _la = self._input.LA(1) if not(_la==81 or _la==82): self._errHandler.recoverInline(self) @@ -8961,11 +8971,11 @@ def execution_decl(self): self.enterRule(localctx, 152, self.RULE_execution_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 910 - self.match(ASLParser.EXECUTIONTYPE) self.state = 911 - self.match(ASLParser.COLON) + self.match(ASLParser.EXECUTIONTYPE) self.state = 912 + self.match(ASLParser.COLON) + self.state = 913 self.execution_type() except RecognitionException as re: localctx.exception = re @@ -9012,7 +9022,7 @@ def execution_type(self): self.enterRule(localctx, 154, self.RULE_execution_type) try: self.enterOuterAlt(localctx, 1) - self.state = 914 + self.state = 915 self.match(ASLParser.STANDARD) except RecognitionException as re: localctx.exception = re @@ -9082,27 +9092,27 @@ def iterator_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 916 - self.match(ASLParser.ITERATOR) self.state = 917 - self.match(ASLParser.COLON) + self.match(ASLParser.ITERATOR) self.state = 918 - self.match(ASLParser.LBRACE) + self.match(ASLParser.COLON) self.state = 919 + self.match(ASLParser.LBRACE) + self.state = 920 self.iterator_decl_item() - self.state = 924 + self.state = 925 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 920 - self.match(ASLParser.COMMA) self.state = 921 + self.match(ASLParser.COMMA) + self.state = 922 self.iterator_decl_item() - self.state = 926 + self.state = 927 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 927 + self.state = 928 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -9161,27 +9171,27 @@ def iterator_decl_item(self): localctx = ASLParser.Iterator_decl_itemContext(self, self._ctx, self.state) self.enterRule(localctx, 158, self.RULE_iterator_decl_item) try: - self.state = 933 + self.state = 934 self._errHandler.sync(self) token = self._input.LA(1) if token in [12]: self.enterOuterAlt(localctx, 1) - self.state = 929 + self.state = 930 self.startat_decl() pass elif token in [11]: self.enterOuterAlt(localctx, 2) - self.state = 930 + self.state = 931 self.states_decl() pass elif token in [10]: self.enterOuterAlt(localctx, 3) - self.state = 931 + self.state = 932 self.comment_decl() pass elif token in [79]: self.enterOuterAlt(localctx, 4) - self.state = 932 + self.state = 933 self.processor_config_decl() pass else: @@ -9239,11 +9249,11 @@ def item_selector_decl(self): self.enterRule(localctx, 160, self.RULE_item_selector_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 935 - self.match(ASLParser.ITEMSELECTOR) self.state = 936 - self.match(ASLParser.COLON) + self.match(ASLParser.ITEMSELECTOR) self.state = 937 + self.match(ASLParser.COLON) + self.state = 938 self.payload_tmpl_decl() except RecognitionException as re: localctx.exception = re @@ -9313,27 +9323,27 @@ def item_reader_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 939 - self.match(ASLParser.ITEMREADER) self.state = 940 - self.match(ASLParser.COLON) + self.match(ASLParser.ITEMREADER) self.state = 941 - self.match(ASLParser.LBRACE) + self.match(ASLParser.COLON) self.state = 942 + self.match(ASLParser.LBRACE) + self.state = 943 self.items_reader_field() - self.state = 947 + self.state = 948 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 943 - self.match(ASLParser.COMMA) self.state = 944 + self.match(ASLParser.COMMA) + self.state = 945 self.items_reader_field() - self.state = 949 + self.state = 950 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 950 + self.state = 951 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -9392,27 +9402,27 @@ def items_reader_field(self): localctx = ASLParser.Items_reader_fieldContext(self, self._ctx, self.state) self.enterRule(localctx, 164, self.RULE_items_reader_field) try: - self.state = 956 + self.state = 957 self._errHandler.sync(self) token = self._input.LA(1) if token in [90]: self.enterOuterAlt(localctx, 1) - self.state = 952 + self.state = 953 self.resource_decl() pass elif token in [101]: self.enterOuterAlt(localctx, 2) - self.state = 953 + self.state = 954 self.reader_config_decl() pass elif token in [97]: self.enterOuterAlt(localctx, 3) - self.state = 954 + self.state = 955 self.parameters_decl() pass elif token in [134]: self.enterOuterAlt(localctx, 4) - self.state = 955 + self.state = 956 self.arguments_decl() pass else: @@ -9486,27 +9496,27 @@ def reader_config_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 958 - self.match(ASLParser.READERCONFIG) self.state = 959 - self.match(ASLParser.COLON) + self.match(ASLParser.READERCONFIG) self.state = 960 - self.match(ASLParser.LBRACE) + self.match(ASLParser.COLON) self.state = 961 + self.match(ASLParser.LBRACE) + self.state = 962 self.reader_config_field() - self.state = 966 + self.state = 967 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 962 - self.match(ASLParser.COMMA) self.state = 963 + self.match(ASLParser.COMMA) + self.state = 964 self.reader_config_field() - self.state = 968 + self.state = 969 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 969 + self.state = 970 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -9569,32 +9579,32 @@ def reader_config_field(self): localctx = ASLParser.Reader_config_fieldContext(self, self._ctx, self.state) self.enterRule(localctx, 168, self.RULE_reader_config_field) try: - self.state = 976 + self.state = 977 self._errHandler.sync(self) token = self._input.LA(1) if token in [102]: self.enterOuterAlt(localctx, 1) - self.state = 971 + self.state = 972 self.input_type_decl() pass elif token in [103]: self.enterOuterAlt(localctx, 2) - self.state = 972 + self.state = 973 self.csv_header_location_decl() pass elif token in [104]: self.enterOuterAlt(localctx, 3) - self.state = 973 + self.state = 974 self.csv_headers_decl() pass elif token in [105]: self.enterOuterAlt(localctx, 4) - self.state = 974 + self.state = 975 self.max_items_decl() pass elif token in [106]: self.enterOuterAlt(localctx, 5) - self.state = 975 + self.state = 976 self.max_items_path_decl() pass else: @@ -9652,11 +9662,11 @@ def input_type_decl(self): self.enterRule(localctx, 170, self.RULE_input_type_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 978 - self.match(ASLParser.INPUTTYPE) self.state = 979 - self.match(ASLParser.COLON) + self.match(ASLParser.INPUTTYPE) self.state = 980 + self.match(ASLParser.COLON) + self.state = 981 self.keyword_or_string() except RecognitionException as re: localctx.exception = re @@ -9710,11 +9720,11 @@ def csv_header_location_decl(self): self.enterRule(localctx, 172, self.RULE_csv_header_location_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 982 - self.match(ASLParser.CSVHEADERLOCATION) self.state = 983 - self.match(ASLParser.COLON) + self.match(ASLParser.CSVHEADERLOCATION) self.state = 984 + self.match(ASLParser.COLON) + self.state = 985 self.keyword_or_string() except RecognitionException as re: localctx.exception = re @@ -9784,27 +9794,27 @@ def csv_headers_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 986 - self.match(ASLParser.CSVHEADERS) self.state = 987 - self.match(ASLParser.COLON) + self.match(ASLParser.CSVHEADERS) self.state = 988 - self.match(ASLParser.LBRACK) + self.match(ASLParser.COLON) self.state = 989 + self.match(ASLParser.LBRACK) + self.state = 990 self.keyword_or_string() - self.state = 994 + self.state = 995 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 990 - self.match(ASLParser.COMMA) self.state = 991 + self.match(ASLParser.COMMA) + self.state = 992 self.keyword_or_string() - self.state = 996 + self.state = 997 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 997 + self.state = 998 self.match(ASLParser.RBRACK) except RecognitionException as re: localctx.exception = re @@ -9894,28 +9904,28 @@ def max_items_decl(self): localctx = ASLParser.Max_items_declContext(self, self._ctx, self.state) self.enterRule(localctx, 176, self.RULE_max_items_decl) try: - self.state = 1005 + self.state = 1006 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,71,self._ctx) if la_ == 1: localctx = ASLParser.Max_items_jsonataContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 999 - self.match(ASLParser.MAXITEMS) self.state = 1000 - self.match(ASLParser.COLON) + self.match(ASLParser.MAXITEMS) self.state = 1001 + self.match(ASLParser.COLON) + self.state = 1002 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 2: localctx = ASLParser.Max_items_intContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 1002 - self.match(ASLParser.MAXITEMS) self.state = 1003 - self.match(ASLParser.COLON) + self.match(ASLParser.MAXITEMS) self.state = 1004 + self.match(ASLParser.COLON) + self.state = 1005 self.match(ASLParser.INT) pass @@ -10009,28 +10019,28 @@ def max_items_path_decl(self): localctx = ASLParser.Max_items_path_declContext(self, self._ctx, self.state) self.enterRule(localctx, 178, self.RULE_max_items_path_decl) try: - self.state = 1013 + self.state = 1014 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,72,self._ctx) if la_ == 1: localctx = ASLParser.Max_items_path_varContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 1007 - self.match(ASLParser.MAXITEMSPATH) self.state = 1008 - self.match(ASLParser.COLON) + self.match(ASLParser.MAXITEMSPATH) self.state = 1009 + self.match(ASLParser.COLON) + self.state = 1010 self.variable_sample() pass elif la_ == 2: localctx = ASLParser.Max_items_pathContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 1010 - self.match(ASLParser.MAXITEMSPATH) self.state = 1011 - self.match(ASLParser.COLON) + self.match(ASLParser.MAXITEMSPATH) self.state = 1012 + self.match(ASLParser.COLON) + self.state = 1013 self.match(ASLParser.STRINGPATH) pass @@ -10123,28 +10133,28 @@ def tolerated_failure_count_decl(self): localctx = ASLParser.Tolerated_failure_count_declContext(self, self._ctx, self.state) self.enterRule(localctx, 180, self.RULE_tolerated_failure_count_decl) try: - self.state = 1021 + self.state = 1022 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,73,self._ctx) if la_ == 1: localctx = ASLParser.Tolerated_failure_count_jsonataContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 1015 - self.match(ASLParser.TOLERATEDFAILURECOUNT) self.state = 1016 - self.match(ASLParser.COLON) + self.match(ASLParser.TOLERATEDFAILURECOUNT) self.state = 1017 + self.match(ASLParser.COLON) + self.state = 1018 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 2: localctx = ASLParser.Tolerated_failure_count_intContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 1018 - self.match(ASLParser.TOLERATEDFAILURECOUNT) self.state = 1019 - self.match(ASLParser.COLON) + self.match(ASLParser.TOLERATEDFAILURECOUNT) self.state = 1020 + self.match(ASLParser.COLON) + self.state = 1021 self.match(ASLParser.INT) pass @@ -10238,28 +10248,28 @@ def tolerated_failure_count_path_decl(self): localctx = ASLParser.Tolerated_failure_count_path_declContext(self, self._ctx, self.state) self.enterRule(localctx, 182, self.RULE_tolerated_failure_count_path_decl) try: - self.state = 1029 + self.state = 1030 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,74,self._ctx) if la_ == 1: localctx = ASLParser.Tolerated_failure_count_path_varContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 1023 - self.match(ASLParser.TOLERATEDFAILURECOUNTPATH) self.state = 1024 - self.match(ASLParser.COLON) + self.match(ASLParser.TOLERATEDFAILURECOUNTPATH) self.state = 1025 + self.match(ASLParser.COLON) + self.state = 1026 self.variable_sample() pass elif la_ == 2: localctx = ASLParser.Tolerated_failure_count_pathContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 1026 - self.match(ASLParser.TOLERATEDFAILURECOUNTPATH) self.state = 1027 - self.match(ASLParser.COLON) + self.match(ASLParser.TOLERATEDFAILURECOUNTPATH) self.state = 1028 + self.match(ASLParser.COLON) + self.state = 1029 self.match(ASLParser.STRINGPATH) pass @@ -10352,28 +10362,28 @@ def tolerated_failure_percentage_decl(self): localctx = ASLParser.Tolerated_failure_percentage_declContext(self, self._ctx, self.state) self.enterRule(localctx, 184, self.RULE_tolerated_failure_percentage_decl) try: - self.state = 1037 + self.state = 1038 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,75,self._ctx) if la_ == 1: localctx = ASLParser.Tolerated_failure_percentage_jsonataContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 1031 - self.match(ASLParser.TOLERATEDFAILUREPERCENTAGE) self.state = 1032 - self.match(ASLParser.COLON) + self.match(ASLParser.TOLERATEDFAILUREPERCENTAGE) self.state = 1033 + self.match(ASLParser.COLON) + self.state = 1034 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 2: localctx = ASLParser.Tolerated_failure_percentage_numberContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 1034 - self.match(ASLParser.TOLERATEDFAILUREPERCENTAGE) self.state = 1035 - self.match(ASLParser.COLON) + self.match(ASLParser.TOLERATEDFAILUREPERCENTAGE) self.state = 1036 + self.match(ASLParser.COLON) + self.state = 1037 self.match(ASLParser.NUMBER) pass @@ -10467,28 +10477,28 @@ def tolerated_failure_percentage_path_decl(self): localctx = ASLParser.Tolerated_failure_percentage_path_declContext(self, self._ctx, self.state) self.enterRule(localctx, 186, self.RULE_tolerated_failure_percentage_path_decl) try: - self.state = 1045 + self.state = 1046 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,76,self._ctx) if la_ == 1: localctx = ASLParser.Tolerated_failure_percentage_path_varContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 1039 - self.match(ASLParser.TOLERATEDFAILUREPERCENTAGEPATH) self.state = 1040 - self.match(ASLParser.COLON) + self.match(ASLParser.TOLERATEDFAILUREPERCENTAGEPATH) self.state = 1041 + self.match(ASLParser.COLON) + self.state = 1042 self.variable_sample() pass elif la_ == 2: localctx = ASLParser.Tolerated_failure_percentage_pathContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 1042 - self.match(ASLParser.TOLERATEDFAILUREPERCENTAGEPATH) self.state = 1043 - self.match(ASLParser.COLON) + self.match(ASLParser.TOLERATEDFAILUREPERCENTAGEPATH) self.state = 1044 + self.match(ASLParser.COLON) + self.state = 1045 self.match(ASLParser.STRINGPATH) pass @@ -10545,11 +10555,11 @@ def label_decl(self): self.enterRule(localctx, 188, self.RULE_label_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 1047 - self.match(ASLParser.LABEL) self.state = 1048 - self.match(ASLParser.COLON) + self.match(ASLParser.LABEL) self.state = 1049 + self.match(ASLParser.COLON) + self.state = 1050 self.keyword_or_string() except RecognitionException as re: localctx.exception = re @@ -10619,27 +10629,27 @@ def result_writer_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1051 - self.match(ASLParser.RESULTWRITER) self.state = 1052 - self.match(ASLParser.COLON) + self.match(ASLParser.RESULTWRITER) self.state = 1053 - self.match(ASLParser.LBRACE) + self.match(ASLParser.COLON) self.state = 1054 + self.match(ASLParser.LBRACE) + self.state = 1055 self.result_writer_field() - self.state = 1059 + self.state = 1060 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1055 - self.match(ASLParser.COMMA) self.state = 1056 + self.match(ASLParser.COMMA) + self.state = 1057 self.result_writer_field() - self.state = 1061 + self.state = 1062 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1062 + self.state = 1063 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -10690,17 +10700,17 @@ def result_writer_field(self): localctx = ASLParser.Result_writer_fieldContext(self, self._ctx, self.state) self.enterRule(localctx, 192, self.RULE_result_writer_field) try: - self.state = 1066 + self.state = 1067 self._errHandler.sync(self) token = self._input.LA(1) if token in [90]: self.enterOuterAlt(localctx, 1) - self.state = 1064 + self.state = 1065 self.resource_decl() pass elif token in [97]: self.enterOuterAlt(localctx, 2) - self.state = 1065 + self.state = 1066 self.parameters_decl() pass else: @@ -10774,33 +10784,33 @@ def retry_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1068 - self.match(ASLParser.RETRY) self.state = 1069 - self.match(ASLParser.COLON) + self.match(ASLParser.RETRY) self.state = 1070 + self.match(ASLParser.COLON) + self.state = 1071 self.match(ASLParser.LBRACK) - self.state = 1079 + self.state = 1080 self._errHandler.sync(self) _la = self._input.LA(1) if _la==5: - self.state = 1071 + self.state = 1072 self.retrier_decl() - self.state = 1076 + self.state = 1077 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1072 - self.match(ASLParser.COMMA) self.state = 1073 + self.match(ASLParser.COMMA) + self.state = 1074 self.retrier_decl() - self.state = 1078 + self.state = 1079 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1081 + self.state = 1082 self.match(ASLParser.RBRACK) except RecognitionException as re: localctx.exception = re @@ -10864,23 +10874,23 @@ def retrier_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1083 - self.match(ASLParser.LBRACE) self.state = 1084 + self.match(ASLParser.LBRACE) + self.state = 1085 self.retrier_stmt() - self.state = 1089 + self.state = 1090 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1085 - self.match(ASLParser.COMMA) self.state = 1086 + self.match(ASLParser.COMMA) + self.state = 1087 self.retrier_stmt() - self.state = 1091 + self.state = 1092 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1092 + self.state = 1093 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -10951,42 +10961,42 @@ def retrier_stmt(self): localctx = ASLParser.Retrier_stmtContext(self, self._ctx, self.state) self.enterRule(localctx, 198, self.RULE_retrier_stmt) try: - self.state = 1101 + self.state = 1102 self._errHandler.sync(self) token = self._input.LA(1) if token in [120]: self.enterOuterAlt(localctx, 1) - self.state = 1094 + self.state = 1095 self.error_equals_decl() pass elif token in [121]: self.enterOuterAlt(localctx, 2) - self.state = 1095 + self.state = 1096 self.interval_seconds_decl() pass elif token in [122]: self.enterOuterAlt(localctx, 3) - self.state = 1096 + self.state = 1097 self.max_attempts_decl() pass elif token in [123]: self.enterOuterAlt(localctx, 4) - self.state = 1097 + self.state = 1098 self.backoff_rate_decl() pass elif token in [124]: self.enterOuterAlt(localctx, 5) - self.state = 1098 + self.state = 1099 self.max_delay_seconds_decl() pass elif token in [125]: self.enterOuterAlt(localctx, 6) - self.state = 1099 + self.state = 1100 self.jitter_strategy_decl() pass elif token in [10]: self.enterOuterAlt(localctx, 7) - self.state = 1100 + self.state = 1101 self.comment_decl() pass else: @@ -11060,27 +11070,27 @@ def error_equals_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1103 - self.match(ASLParser.ERROREQUALS) self.state = 1104 - self.match(ASLParser.COLON) + self.match(ASLParser.ERROREQUALS) self.state = 1105 - self.match(ASLParser.LBRACK) + self.match(ASLParser.COLON) self.state = 1106 + self.match(ASLParser.LBRACK) + self.state = 1107 self.error_name() - self.state = 1111 + self.state = 1112 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1107 - self.match(ASLParser.COMMA) self.state = 1108 + self.match(ASLParser.COMMA) + self.state = 1109 self.error_name() - self.state = 1113 + self.state = 1114 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1114 + self.state = 1115 self.match(ASLParser.RBRACK) except RecognitionException as re: localctx.exception = re @@ -11133,11 +11143,11 @@ def interval_seconds_decl(self): self.enterRule(localctx, 202, self.RULE_interval_seconds_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 1116 - self.match(ASLParser.INTERVALSECONDS) self.state = 1117 - self.match(ASLParser.COLON) + self.match(ASLParser.INTERVALSECONDS) self.state = 1118 + self.match(ASLParser.COLON) + self.state = 1119 self.match(ASLParser.INT) except RecognitionException as re: localctx.exception = re @@ -11190,11 +11200,11 @@ def max_attempts_decl(self): self.enterRule(localctx, 204, self.RULE_max_attempts_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 1120 - self.match(ASLParser.MAXATTEMPTS) self.state = 1121 - self.match(ASLParser.COLON) + self.match(ASLParser.MAXATTEMPTS) self.state = 1122 + self.match(ASLParser.COLON) + self.state = 1123 self.match(ASLParser.INT) except RecognitionException as re: localctx.exception = re @@ -11251,11 +11261,11 @@ def backoff_rate_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1124 - self.match(ASLParser.BACKOFFRATE) self.state = 1125 - self.match(ASLParser.COLON) + self.match(ASLParser.BACKOFFRATE) self.state = 1126 + self.match(ASLParser.COLON) + self.state = 1127 _la = self._input.LA(1) if not(_la==158 or _la==159): self._errHandler.recoverInline(self) @@ -11313,11 +11323,11 @@ def max_delay_seconds_decl(self): self.enterRule(localctx, 208, self.RULE_max_delay_seconds_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 1128 - self.match(ASLParser.MAXDELAYSECONDS) self.state = 1129 - self.match(ASLParser.COLON) + self.match(ASLParser.MAXDELAYSECONDS) self.state = 1130 + self.match(ASLParser.COLON) + self.state = 1131 self.match(ASLParser.INT) except RecognitionException as re: localctx.exception = re @@ -11374,11 +11384,11 @@ def jitter_strategy_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1132 - self.match(ASLParser.JITTERSTRATEGY) self.state = 1133 - self.match(ASLParser.COLON) + self.match(ASLParser.JITTERSTRATEGY) self.state = 1134 + self.match(ASLParser.COLON) + self.state = 1135 _la = self._input.LA(1) if not(_la==126 or _la==127): self._errHandler.recoverInline(self) @@ -11453,33 +11463,33 @@ def catch_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1136 - self.match(ASLParser.CATCH) self.state = 1137 - self.match(ASLParser.COLON) + self.match(ASLParser.CATCH) self.state = 1138 + self.match(ASLParser.COLON) + self.state = 1139 self.match(ASLParser.LBRACK) - self.state = 1147 + self.state = 1148 self._errHandler.sync(self) _la = self._input.LA(1) if _la==5: - self.state = 1139 + self.state = 1140 self.catcher_decl() - self.state = 1144 + self.state = 1145 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1140 - self.match(ASLParser.COMMA) self.state = 1141 + self.match(ASLParser.COMMA) + self.state = 1142 self.catcher_decl() - self.state = 1146 + self.state = 1147 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1149 + self.state = 1150 self.match(ASLParser.RBRACK) except RecognitionException as re: localctx.exception = re @@ -11543,23 +11553,23 @@ def catcher_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1151 - self.match(ASLParser.LBRACE) self.state = 1152 + self.match(ASLParser.LBRACE) + self.state = 1153 self.catcher_stmt() - self.state = 1157 + self.state = 1158 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1153 - self.match(ASLParser.COMMA) self.state = 1154 + self.match(ASLParser.COMMA) + self.state = 1155 self.catcher_stmt() - self.state = 1159 + self.state = 1160 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1160 + self.state = 1161 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -11626,37 +11636,37 @@ def catcher_stmt(self): localctx = ASLParser.Catcher_stmtContext(self, self._ctx, self.state) self.enterRule(localctx, 216, self.RULE_catcher_stmt) try: - self.state = 1168 + self.state = 1169 self._errHandler.sync(self) token = self._input.LA(1) if token in [120]: self.enterOuterAlt(localctx, 1) - self.state = 1162 + self.state = 1163 self.error_equals_decl() pass elif token in [95]: self.enterOuterAlt(localctx, 2) - self.state = 1163 + self.state = 1164 self.result_path_decl() pass elif token in [113]: self.enterOuterAlt(localctx, 3) - self.state = 1164 + self.state = 1165 self.next_decl() pass elif token in [132]: self.enterOuterAlt(localctx, 4) - self.state = 1165 + self.state = 1166 self.assign_decl() pass elif token in [133]: self.enterOuterAlt(localctx, 5) - self.state = 1166 + self.state = 1167 self.output_decl() pass elif token in [10]: self.enterOuterAlt(localctx, 6) - self.state = 1167 + self.state = 1168 self.comment_decl() pass else: @@ -11822,7 +11832,7 @@ def comparison_op(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1170 + self.state = 1171 _la = self._input.LA(1) if not(((((_la - 30)) & ~0x3f) == 0 and ((1 << (_la - 30)) & 2199022731007) != 0)): self._errHandler.recoverInline(self) @@ -11881,7 +11891,7 @@ def choice_operator(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1172 + self.state = 1173 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & 563225368199168) != 0)): self._errHandler.recoverInline(self) @@ -11979,7 +11989,7 @@ def states_error_name(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1174 + self.state = 1175 _la = self._input.LA(1) if not(((((_la - 135)) & ~0x3f) == 0 and ((1 << (_la - 135)) & 65535) != 0)): self._errHandler.recoverInline(self) @@ -12035,18 +12045,18 @@ def error_name(self): localctx = ASLParser.Error_nameContext(self, self._ctx, self.state) self.enterRule(localctx, 224, self.RULE_error_name) try: - self.state = 1178 + self.state = 1179 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,88,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 1176 + self.state = 1177 self.states_error_name() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 1177 + self.state = 1178 self.keyword_or_string() pass @@ -12112,36 +12122,36 @@ def json_obj_decl(self): self.enterRule(localctx, 226, self.RULE_json_obj_decl) self._la = 0 # Token type try: - self.state = 1193 + self.state = 1194 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,90,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 1180 - self.match(ASLParser.LBRACE) self.state = 1181 + self.match(ASLParser.LBRACE) + self.state = 1182 self.json_binding() - self.state = 1186 + self.state = 1187 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1182 - self.match(ASLParser.COMMA) self.state = 1183 + self.match(ASLParser.COMMA) + self.state = 1184 self.json_binding() - self.state = 1188 + self.state = 1189 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1189 + self.state = 1190 self.match(ASLParser.RBRACE) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 1191 - self.match(ASLParser.LBRACE) self.state = 1192 + self.match(ASLParser.LBRACE) + self.state = 1193 self.match(ASLParser.RBRACE) pass @@ -12199,11 +12209,11 @@ def json_binding(self): self.enterRule(localctx, 228, self.RULE_json_binding) try: self.enterOuterAlt(localctx, 1) - self.state = 1195 - self.keyword_or_string() self.state = 1196 - self.match(ASLParser.COLON) + self.keyword_or_string() self.state = 1197 + self.match(ASLParser.COLON) + self.state = 1198 self.json_value_decl() except RecognitionException as re: localctx.exception = re @@ -12266,36 +12276,36 @@ def json_arr_decl(self): self.enterRule(localctx, 230, self.RULE_json_arr_decl) self._la = 0 # Token type try: - self.state = 1212 + self.state = 1213 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,92,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 1199 - self.match(ASLParser.LBRACK) self.state = 1200 + self.match(ASLParser.LBRACK) + self.state = 1201 self.json_value_decl() - self.state = 1205 + self.state = 1206 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1201 - self.match(ASLParser.COMMA) self.state = 1202 + self.match(ASLParser.COMMA) + self.state = 1203 self.json_value_decl() - self.state = 1207 + self.state = 1208 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1208 + self.state = 1209 self.match(ASLParser.RBRACK) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 1210 - self.match(ASLParser.LBRACK) self.state = 1211 + self.match(ASLParser.LBRACK) + self.state = 1212 self.match(ASLParser.RBRACK) pass @@ -12372,60 +12382,60 @@ def json_value_decl(self): localctx = ASLParser.Json_value_declContext(self, self._ctx, self.state) self.enterRule(localctx, 232, self.RULE_json_value_decl) try: - self.state = 1223 + self.state = 1224 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,93,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 1214 + self.state = 1215 self.match(ASLParser.NUMBER) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 1215 + self.state = 1216 self.match(ASLParser.INT) pass elif la_ == 3: self.enterOuterAlt(localctx, 3) - self.state = 1216 + self.state = 1217 self.match(ASLParser.TRUE) pass elif la_ == 4: self.enterOuterAlt(localctx, 4) - self.state = 1217 + self.state = 1218 self.match(ASLParser.FALSE) pass elif la_ == 5: self.enterOuterAlt(localctx, 5) - self.state = 1218 + self.state = 1219 self.match(ASLParser.NULL) pass elif la_ == 6: self.enterOuterAlt(localctx, 6) - self.state = 1219 + self.state = 1220 self.json_binding() pass elif la_ == 7: self.enterOuterAlt(localctx, 7) - self.state = 1220 + self.state = 1221 self.json_arr_decl() pass elif la_ == 8: self.enterOuterAlt(localctx, 8) - self.state = 1221 + self.state = 1222 self.json_obj_decl() pass elif la_ == 9: self.enterOuterAlt(localctx, 9) - self.state = 1222 + self.state = 1223 self.keyword_or_string() pass @@ -12899,7 +12909,7 @@ def keyword_or_string(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1225 + self.state = 1226 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & -17408) != 0) or ((((_la - 64)) & ~0x3f) == 0 and ((1 << (_la - 64)) & -22517998136852481) != 0) or ((((_la - 128)) & ~0x3f) == 0 and ((1 << (_la - 128)) & 1073741555) != 0)): self._errHandler.recoverInline(self) diff --git a/tests/aws/services/stepfunctions/templates/comment/statemachines/comments_as_per_docs.json5 b/tests/aws/services/stepfunctions/templates/comment/statemachines/comments_as_per_docs.json5 index 16d5f1ff49973..ff82531cfaa55 100644 --- a/tests/aws/services/stepfunctions/templates/comment/statemachines/comments_as_per_docs.json5 +++ b/tests/aws/services/stepfunctions/templates/comment/statemachines/comments_as_per_docs.json5 @@ -49,6 +49,7 @@ "Comment": "If task is complete, move to the SuccessState." } ], + "Comment": "Set the next state as the SuccessState", "Next": "SuccessState" } ], diff --git a/tests/aws/services/stepfunctions/v2/comments/test_comments.py b/tests/aws/services/stepfunctions/v2/comments/test_comments.py index 624f4c8e808fe..fcebcb9c68515 100644 --- a/tests/aws/services/stepfunctions/v2/comments/test_comments.py +++ b/tests/aws/services/stepfunctions/v2/comments/test_comments.py @@ -2,6 +2,7 @@ from localstack_snapshot.snapshots.transformer import RegexTransformer +from localstack.aws.api.lambda_ import Runtime from localstack.testing.pytest import markers from localstack.testing.pytest.stepfunctions.utils import create_and_record_execution from localstack.utils.strings import short_uid @@ -13,7 +14,6 @@ ) -@markers.snapshot.skip_snapshot_verify(paths=["$..tracingConfiguration"]) class TestComments: @markers.aws.validated def test_comments_as_per_docs( @@ -28,7 +28,7 @@ def test_comments_as_per_docs( create_1_res = create_lambda_function( func_name=function_1_name, handler_file=ST.LAMBDA_ID_FUNCTION, - runtime="python3.9", + runtime=Runtime.python3_12, ) sfn_snapshot.add_transformer(RegexTransformer(function_1_name, "lambda_function_1_name")) diff --git a/tests/aws/services/stepfunctions/v2/comments/test_comments.snapshot.json b/tests/aws/services/stepfunctions/v2/comments/test_comments.snapshot.json index dedab3c5d64d5..4a912fc31db05 100644 --- a/tests/aws/services/stepfunctions/v2/comments/test_comments.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/comments/test_comments.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/stepfunctions/v2/comments/test_comments.py::TestComments::test_comments_as_per_docs": { - "recorded-date": "09-02-2024, 11:23:55", + "recorded-date": "28-11-2024, 10:33:23", "recorded-content": { "get_execution_history": { "events": [ @@ -348,7 +348,7 @@ } }, "tests/aws/services/stepfunctions/v2/comments/test_comments.py::TestComments::test_comment_in_parameters": { - "recorded-date": "09-02-2024, 12:06:30", + "recorded-date": "28-11-2024, 10:33:37", "recorded-content": { "get_execution_history": { "events": [ diff --git a/tests/aws/services/stepfunctions/v2/comments/test_comments.validation.json b/tests/aws/services/stepfunctions/v2/comments/test_comments.validation.json index 77b2c05f91470..e16a0a8487ed7 100644 --- a/tests/aws/services/stepfunctions/v2/comments/test_comments.validation.json +++ b/tests/aws/services/stepfunctions/v2/comments/test_comments.validation.json @@ -1,8 +1,8 @@ { "tests/aws/services/stepfunctions/v2/comments/test_comments.py::TestComments::test_comment_in_parameters": { - "last_validated_date": "2024-02-09T12:06:30+00:00" + "last_validated_date": "2024-11-28T10:33:37+00:00" }, "tests/aws/services/stepfunctions/v2/comments/test_comments.py::TestComments::test_comments_as_per_docs": { - "last_validated_date": "2024-02-09T11:23:55+00:00" + "last_validated_date": "2024-11-28T10:33:23+00:00" } -} \ No newline at end of file +} From 5a2a3f8605bcfe9c6bc21dc75b6d9c2e52db4c9c Mon Sep 17 00:00:00 2001 From: Ben Simon Hartung <42031100+bentsku@users.noreply.github.com> Date: Fri, 29 Nov 2024 08:29:51 +0100 Subject: [PATCH 26/38] fix ESM analytics (#11961) --- .../lambda_/event_source_mapping/esm_event_processor.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/localstack-core/localstack/services/lambda_/event_source_mapping/esm_event_processor.py b/localstack-core/localstack/services/lambda_/event_source_mapping/esm_event_processor.py index f70d2e3b78a42..2ecfb61461a17 100644 --- a/localstack-core/localstack/services/lambda_/event_source_mapping/esm_event_processor.py +++ b/localstack-core/localstack/services/lambda_/event_source_mapping/esm_event_processor.py @@ -28,9 +28,14 @@ def __init__(self, sender, logger): self.sender = sender self.logger = logger - def process_events_batch(self, input_events: list[dict]) -> None: + def process_events_batch(self, input_events: list[dict] | dict) -> None: # analytics - first_event = input_events[0] if input_events else {} + if isinstance(input_events, list) and input_events: + first_event = input_events[0] + elif input_events: + first_event = input_events + else: + first_event = {} event_source = first_event.get("eventSource") esm_invocation.record(event_source) From be61d50d827ea02c500f50a496d14554ba6384ca Mon Sep 17 00:00:00 2001 From: Mathieu Cloutier <79954947+cloutierMat@users.noreply.github.com> Date: Fri, 29 Nov 2024 02:16:55 -0700 Subject: [PATCH 27/38] Implement read operation for AWS::SSM::Parameter & update resource spec (#11962) --- .../services/cloudformation/engine/quirks.py | 1 - .../services/cloudformation/provider_utils.py | 2 +- .../resource_providers/aws_ssm_parameter.py | 51 +++++--- .../aws_ssm_parameter.schema.json | 113 ++++++++++++++---- .../localstack/utils/aws/client_types.py | 1 + 5 files changed, 130 insertions(+), 38 deletions(-) diff --git a/localstack-core/localstack/services/cloudformation/engine/quirks.py b/localstack-core/localstack/services/cloudformation/engine/quirks.py index 1a94e190180e2..b38056474b560 100644 --- a/localstack-core/localstack/services/cloudformation/engine/quirks.py +++ b/localstack-core/localstack/services/cloudformation/engine/quirks.py @@ -28,7 +28,6 @@ "AWS::Events::EventBus": "/properties/Name", "AWS::Logs::LogStream": "/properties/LogStreamName", "AWS::Logs::SubscriptionFilter": "/properties/LogGroupName", - "AWS::SSM::Parameter": "/properties/Name", "AWS::RDS::DBProxyTargetGroup": "/properties/TargetGroupName", "AWS::Glue::SchemaVersionMetadata": "||", # composite "AWS::WAFv2::WebACL": "||", diff --git a/localstack-core/localstack/services/cloudformation/provider_utils.py b/localstack-core/localstack/services/cloudformation/provider_utils.py index 61ff85d831d3c..a69c69a17ba7c 100644 --- a/localstack-core/localstack/services/cloudformation/provider_utils.py +++ b/localstack-core/localstack/services/cloudformation/provider_utils.py @@ -227,7 +227,7 @@ def recursive_convert(obj): # LocalStack specific utilities -def get_schema_path(file_path: Path) -> Path: +def get_schema_path(file_path: Path) -> dict: file_name_base = file_path.name.removesuffix(".py").removesuffix(".py.enc") with Path(file_path).parent.joinpath(f"{file_name_base}.schema.json").open() as fd: return json.load(fd) diff --git a/localstack-core/localstack/services/ssm/resource_providers/aws_ssm_parameter.py b/localstack-core/localstack/services/ssm/resource_providers/aws_ssm_parameter.py index 1f5a438a2fc5f..16c9109270926 100644 --- a/localstack-core/localstack/services/ssm/resource_providers/aws_ssm_parameter.py +++ b/localstack-core/localstack/services/ssm/resource_providers/aws_ssm_parameter.py @@ -19,7 +19,6 @@ class SSMParameterProperties(TypedDict): AllowedPattern: Optional[str] DataType: Optional[str] Description: Optional[str] - Id: Optional[str] Name: Optional[str] Policies: Optional[str] Tags: Optional[dict] @@ -41,19 +40,21 @@ def create( Create a new resource. Primary identifier fields: - - /properties/Id + - /properties/Name Required properties: - - Type - Value + - Type Create-only properties: - /properties/Name - Read-only properties: - - /properties/Id + IAM permissions required: + - ssm:PutParameter + - ssm:AddTagsToResource + - ssm:GetParameters """ model = request.desired_state @@ -87,11 +88,7 @@ def create( ssm.put_parameter(**params) - return ProgressEvent( - status=OperationStatus.SUCCESS, - resource_model=model, - custom_context=request.custom_context, - ) + return self.read(request) def read( self, @@ -100,9 +97,27 @@ def read( """ Fetch resource information - + IAM permissions required: + - ssm:GetParameters """ - raise NotImplementedError + ssm = request.aws_client_factory.ssm + parameter_name = request.desired_state.get("Name") + try: + resource = ssm.get_parameter(Name=parameter_name, WithDecryption=False) + except ssm.exceptions.ParameterNotFound: + return ProgressEvent( + status=OperationStatus.FAILED, + message=f"Resource of type '{self.TYPE}' with identifier '{parameter_name}' was not found.", + error_code="NotFound", + ) + + parameter = util.select_attributes(resource["Parameter"], params=self.SCHEMA["properties"]) + + return ProgressEvent( + status=OperationStatus.SUCCESS, + resource_model=parameter, + custom_context=request.custom_context, + ) def delete( self, @@ -111,7 +126,8 @@ def delete( """ Delete a resource - + IAM permissions required: + - ssm:DeleteParameter """ model = request.desired_state ssm = request.aws_client_factory.ssm @@ -131,7 +147,11 @@ def update( """ Update a resource - + IAM permissions required: + - ssm:PutParameter + - ssm:AddTagsToResource + - ssm:RemoveTagsFromResource + - ssm:GetParameters """ model = request.desired_state ssm = request.aws_client_factory.ssm @@ -203,6 +223,7 @@ def list( return ProgressEvent( status=OperationStatus.SUCCESS, resource_models=[ - SSMParameterProperties(Id=resource["Name"]) for resource in resources["Parameters"] + SSMParameterProperties(Name=resource["Name"]) + for resource in resources["Parameters"] ], ) diff --git a/localstack-core/localstack/services/ssm/resource_providers/aws_ssm_parameter.schema.json b/localstack-core/localstack/services/ssm/resource_providers/aws_ssm_parameter.schema.json index c36a381b90f68..9d3e47882fd3d 100644 --- a/localstack-core/localstack/services/ssm/resource_providers/aws_ssm_parameter.schema.json +++ b/localstack-core/localstack/services/ssm/resource_providers/aws_ssm_parameter.schema.json @@ -4,47 +4,118 @@ "additionalProperties": false, "properties": { "Type": { - "type": "string" + "type": "string", + "description": "The type of the parameter.", + "enum": [ + "String", + "StringList", + "SecureString" + ] + }, + "Value": { + "type": "string", + "description": "The value associated with the parameter." }, "Description": { - "type": "string" + "type": "string", + "description": "The information about the parameter." }, "Policies": { - "type": "string" + "type": "string", + "description": "The policies attached to the parameter." }, "AllowedPattern": { - "type": "string" + "type": "string", + "description": "The regular expression used to validate the parameter value." }, "Tier": { - "type": "string" + "type": "string", + "description": "The corresponding tier of the parameter.", + "enum": [ + "Standard", + "Advanced", + "Intelligent-Tiering" + ] }, - "Value": { - "type": "string" + "Tags": { + "type": "object", + "description": "A key-value pair to associate with a resource.", + "patternProperties": { + "^([\\p{L}\\p{Z}\\p{N}_.:/=+\\-@]*)$": { + "type": "string" + } + }, + "additionalProperties": false }, "DataType": { - "type": "string" - }, - "Id": { - "type": "string" - }, - "Tags": { - "type": "object" + "type": "string", + "description": "The corresponding DataType of the parameter.", + "enum": [ + "text", + "aws:ec2:image" + ] }, "Name": { - "type": "string" + "type": "string", + "description": "The name of the parameter." } }, "required": [ - "Type", - "Value" + "Value", + "Type" ], + "tagging": { + "taggable": true, + "tagOnCreate": true, + "tagUpdatable": true, + "cloudFormationSystemTags": true, + "tagProperty": "/properties/Tags" + }, "createOnlyProperties": [ "/properties/Name" ], "primaryIdentifier": [ - "/properties/Id" + "/properties/Name" + ], + "writeOnlyProperties": [ + "/properties/Tags", + "/properties/Description", + "/properties/Tier", + "/properties/AllowedPattern", + "/properties/Policies" ], - "readOnlyProperties": [ - "/properties/Id" - ] + "handlers": { + "create": { + "permissions": [ + "ssm:PutParameter", + "ssm:AddTagsToResource", + "ssm:GetParameters" + ], + "timeoutInMinutes": 5 + }, + "read": { + "permissions": [ + "ssm:GetParameters" + ] + }, + "update": { + "permissions": [ + "ssm:PutParameter", + "ssm:AddTagsToResource", + "ssm:RemoveTagsFromResource", + "ssm:GetParameters" + ], + "timeoutInMinutes": 5 + }, + "delete": { + "permissions": [ + "ssm:DeleteParameter" + ] + }, + "list": { + "permissions": [ + "ssm:DescribeParameters" + ] + } + } } diff --git a/localstack-core/localstack/utils/aws/client_types.py b/localstack-core/localstack/utils/aws/client_types.py index 89d0bb6cf79b7..3df4095c78ef3 100644 --- a/localstack-core/localstack/utils/aws/client_types.py +++ b/localstack-core/localstack/utils/aws/client_types.py @@ -264,6 +264,7 @@ class ServicePrincipal(str): """ apigateway = "apigateway" + cloudformation = "cloudformation" dms = "dms" events = "events" firehose = "firehose" From 2b405dce5c9b7d8e4324287a0f59003635c0bc87 Mon Sep 17 00:00:00 2001 From: Giovanni Grano Date: Fri, 29 Nov 2024 04:20:34 -0500 Subject: [PATCH 28/38] Handle null value in SES OpenAPI spec (#11954) --- localstack-core/localstack/openapi.yaml | 2 +- localstack-core/localstack/services/ses/models.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/localstack-core/localstack/openapi.yaml b/localstack-core/localstack/openapi.yaml index f1932daf0a179..1a78bfe3d0e28 100644 --- a/localstack-core/localstack/openapi.yaml +++ b/localstack-core/localstack/openapi.yaml @@ -158,7 +158,7 @@ components: additionalProperties: false properties: html_part: - type: string + type: [string, 'null'] text_part: type: string required: diff --git a/localstack-core/localstack/services/ses/models.py b/localstack-core/localstack/services/ses/models.py index 778f75dcc484a..2560f872410da 100644 --- a/localstack-core/localstack/services/ses/models.py +++ b/localstack-core/localstack/services/ses/models.py @@ -4,7 +4,7 @@ class SentEmailBody(TypedDict): - html_part: str + html_part: str | None text_part: str From 6bc1e1e5758b88a0282f0e1ba1ff7ec5f17ecf70 Mon Sep 17 00:00:00 2001 From: MEPalma <64580864+MEPalma@users.noreply.github.com> Date: Fri, 29 Nov 2024 11:35:25 +0100 Subject: [PATCH 29/38] StepFunctions: Fix ErrorName Value for Lambda Task Errors (#11957) --- .../service/state_task_service_lambda.py | 17 +- .../state_task/state_task_lambda.py | 17 +- .../errorhandling/error_handling_templates.py | 11 + .../lambdafunctions/raise_custom_exception.py | 9 + .../task_lambda_invoke_catch_tbd.json5 | 24 + ...task_service_lambda_invoke_catch_tbd.json5 | 28 ++ .../v2/error_handling/test_task_lambda.py | 51 +- .../test_task_lambda.snapshot.json | 155 +++++- .../test_task_lambda.validation.json | 11 +- .../test_task_service_lambda.py | 42 +- .../test_task_service_lambda.snapshot.json | 456 ++++++++++++------ .../test_task_service_lambda.validation.json | 19 +- 12 files changed, 650 insertions(+), 190 deletions(-) create mode 100644 tests/aws/services/stepfunctions/templates/errorhandling/lambdafunctions/raise_custom_exception.py create mode 100644 tests/aws/services/stepfunctions/templates/errorhandling/statemachines/task_lambda_invoke_catch_tbd.json5 create mode 100644 tests/aws/services/stepfunctions/templates/errorhandling/statemachines/task_service_lambda_invoke_catch_tbd.json5 diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_lambda.py b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_lambda.py index fd8532a1b779f..88e7b6b5e20b3 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_lambda.py +++ b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_lambda.py @@ -1,3 +1,5 @@ +import json +import logging from typing import Final, Optional from botocore.exceptions import ClientError @@ -22,6 +24,9 @@ from localstack.services.stepfunctions.asl.eval.environment import Environment from localstack.services.stepfunctions.asl.eval.event.event_detail import EventDetails +LOG = logging.getLogger(__name__) + + _SUPPORTED_INTEGRATION_PATTERNS: Final[set[ResourceCondition]] = { ResourceCondition.WaitForTaskToken, } @@ -64,9 +69,17 @@ def _error_cause_from_client_error(client_error: ClientError) -> tuple[str, str] def _from_error(self, env: Environment, ex: Exception) -> FailureEvent: if isinstance(ex, lambda_eval_utils.LambdaFunctionErrorException): - error = "Exception" - error_name = CustomErrorName(error) cause = ex.payload + try: + cause_object = json.loads(cause) + error = cause_object["errorType"] + except Exception as ex: + LOG.warning( + "Could not retrieve 'errorType' field from LambdaFunctionErrorException object: %s", + ex, + ) + error = "Exception" + error_name = CustomErrorName(error) elif isinstance(ex, ClientError): error, cause = self._error_cause_from_client_error(ex) error_name = CustomErrorName(error) diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/state_task_lambda.py b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/state_task_lambda.py index bcaaba7f0b40d..fbf02ad80621a 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/state_task_lambda.py +++ b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/state_task_lambda.py @@ -1,4 +1,5 @@ import json +import logging from typing import Union from botocore.exceptions import ClientError @@ -40,6 +41,8 @@ from localstack.services.stepfunctions.asl.utils.encoding import to_json_str from localstack.services.stepfunctions.quotas import is_within_size_quota +LOG = logging.getLogger(__name__) + class StateTaskLambda(StateTask): resource: LambdaResource @@ -60,12 +63,20 @@ def _from_error(self, env: Environment, ex: Exception) -> FailureEvent: return ex.failure_event error = "Exception" - if isinstance(ex, lambda_eval_utils.LambdaFunctionErrorException): + if isinstance(ex, ClientError): error_name = CustomErrorName(error) + cause = ex.response["Error"]["Message"] + elif isinstance(ex, lambda_eval_utils.LambdaFunctionErrorException): cause = ex.payload - elif isinstance(ex, ClientError): + try: + cause_object = json.loads(cause) + error = cause_object["errorType"] + except Exception as ex: + LOG.warning( + "Could not retrieve 'errorType' field from LambdaFunctionErrorException object: %s", + ex, + ) error_name = CustomErrorName(error) - cause = ex.response["Error"]["Message"] else: error_name = StatesErrorName(StatesErrorNameType.StatesTaskFailed) cause = str(ex) diff --git a/tests/aws/services/stepfunctions/templates/errorhandling/error_handling_templates.py b/tests/aws/services/stepfunctions/templates/errorhandling/error_handling_templates.py index 7632e7cd05f71..881e5a37d7906 100644 --- a/tests/aws/services/stepfunctions/templates/errorhandling/error_handling_templates.py +++ b/tests/aws/services/stepfunctions/templates/errorhandling/error_handling_templates.py @@ -28,6 +28,10 @@ class ErrorHandlingTemplate(TemplateLoader): _THIS_FOLDER, "statemachines/task_lambda_invoke_catch_unknown.json5" ) + AWS_LAMBDA_INVOKE_CATCH_TBD: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/task_lambda_invoke_catch_tbd.json5" + ) + AWS_LAMBDA_INVOKE_CATCH_RELEVANT: Final[str] = os.path.join( _THIS_FOLDER, "statemachines/task_lambda_invoke_catch_relevant.json5" ) @@ -56,6 +60,10 @@ class ErrorHandlingTemplate(TemplateLoader): _THIS_FOLDER, "statemachines/task_service_lambda_invoke_catch_relevant.json5" ) + AWS_SERVICE_LAMBDA_INVOKE_CATCH_TBD: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/task_service_lambda_invoke_catch_tbd.json5" + ) + AWS_SERVICE_SQS_SEND_MSG_CATCH: Final[str] = os.path.join( _THIS_FOLDER, "statemachines/task_service_sqs_send_msg_catch.json5" ) @@ -71,3 +79,6 @@ class ErrorHandlingTemplate(TemplateLoader): LAMBDA_FUNC_RAISE_EXCEPTION: Final[str] = os.path.join( _THIS_FOLDER, "lambdafunctions/raise_exception.py" ) + LAMBDA_FUNC_RAISE_CUSTOM_EXCEPTION: Final[str] = os.path.join( + _THIS_FOLDER, "lambdafunctions/raise_custom_exception.py" + ) diff --git a/tests/aws/services/stepfunctions/templates/errorhandling/lambdafunctions/raise_custom_exception.py b/tests/aws/services/stepfunctions/templates/errorhandling/lambdafunctions/raise_custom_exception.py new file mode 100644 index 0000000000000..38f24d3782a68 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/errorhandling/lambdafunctions/raise_custom_exception.py @@ -0,0 +1,9 @@ +class CustomException(Exception): + message: str + + def __init__(self): + self.message = "CustomException message" + + +def handler(event, context): + raise CustomException() diff --git a/tests/aws/services/stepfunctions/templates/errorhandling/statemachines/task_lambda_invoke_catch_tbd.json5 b/tests/aws/services/stepfunctions/templates/errorhandling/statemachines/task_lambda_invoke_catch_tbd.json5 new file mode 100644 index 0000000000000..ef3f2e24cc45b --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/errorhandling/statemachines/task_lambda_invoke_catch_tbd.json5 @@ -0,0 +1,24 @@ +{ + "StartAt": "InvokeLambda", + "States": { + "InvokeLambda": { + "Type": "Task", + "Resource": "_tbd_", + "Next": "ProcessResult", + "Catch": [ + { + "ErrorEquals": [], + "Next": "ErrorMatched" + } + ] + }, + "ProcessResult": { + "Type": "Pass", + "End": true + }, + "ErrorMatched": { + "Type": "Pass", + "End": true + } + } +} diff --git a/tests/aws/services/stepfunctions/templates/errorhandling/statemachines/task_service_lambda_invoke_catch_tbd.json5 b/tests/aws/services/stepfunctions/templates/errorhandling/statemachines/task_service_lambda_invoke_catch_tbd.json5 new file mode 100644 index 0000000000000..02c08d1b053f1 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/errorhandling/statemachines/task_service_lambda_invoke_catch_tbd.json5 @@ -0,0 +1,28 @@ +{ + "StartAt": "InvokeLambda", + "States": { + "InvokeLambda": { + "Type": "Task", + "Resource": "arn:aws:states:::lambda:invoke", + "Parameters": { + "FunctionName.$": "$.FunctionName", + "Payload.$": "$.Payload", + }, + "Next": "ProcessResult", + "Catch": [ + { + "ErrorEquals": [], + "Next": "ErrorMatched" + } + ] + }, + "ProcessResult": { + "Type": "Pass", + "End": true + }, + "ErrorMatched": { + "Type": "Pass", + "End": true + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py b/tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py index c4711a7be27b0..ffef223030f7a 100644 --- a/tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py +++ b/tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py @@ -2,6 +2,7 @@ from localstack_snapshot.snapshots.transformer import RegexTransformer +from localstack.aws.api.lambda_ import Runtime from localstack.testing.pytest import markers from localstack.testing.pytest.stepfunctions.utils import ( create_and_record_execution, @@ -12,13 +13,7 @@ ) -@markers.snapshot.skip_snapshot_verify( - paths=[ - "$..tracingConfiguration", - "$..cause", - "$..Cause", - ] -) +@markers.snapshot.skip_snapshot_verify(paths=["$..Cause"]) class TestTaskLambda: @markers.aws.validated def test_raise_exception( @@ -33,7 +28,7 @@ def test_raise_exception( create_res = create_lambda_function( func_name=function_name, handler_file=EHT.LAMBDA_FUNC_RAISE_EXCEPTION, - runtime="python3.9", + runtime=Runtime.python3_12, ) sfn_snapshot.add_transformer(RegexTransformer(function_name, "")) @@ -53,6 +48,40 @@ def test_raise_exception( exec_input, ) + @markers.aws.validated + def test_raise_custom_exception( + self, + aws_client, + create_iam_role_for_sfn, + create_state_machine, + create_lambda_function, + sfn_snapshot, + ): + function_name = f"lambda_func_{short_uid()}" + create_res = create_lambda_function( + func_name=function_name, + handler_file=EHT.LAMBDA_FUNC_RAISE_CUSTOM_EXCEPTION, + runtime=Runtime.python3_12, + ) + sfn_snapshot.add_transformer(RegexTransformer(function_name, "")) + + template = EHT.load_sfn_template(EHT.AWS_LAMBDA_INVOKE_CATCH_TBD) + template["States"]["InvokeLambda"]["Resource"] = create_res["CreateFunctionResponse"][ + "FunctionArn" + ] + template["States"]["InvokeLambda"]["Catch"][0]["ErrorEquals"].append("CustomException") + definition = json.dumps(template) + + exec_input = json.dumps({"FunctionName": function_name, "Payload": None}) + create_and_record_execution( + aws_client.stepfunctions, + create_iam_role_for_sfn, + create_state_machine, + sfn_snapshot, + definition, + exec_input, + ) + @markers.aws.validated def test_raise_exception_catch( self, @@ -66,7 +95,7 @@ def test_raise_exception_catch( create_res = create_lambda_function( func_name=function_name, handler_file=EHT.LAMBDA_FUNC_RAISE_EXCEPTION, - runtime="python3.9", + runtime=Runtime.python3_12, ) sfn_snapshot.add_transformer(RegexTransformer(function_name, "")) @@ -99,7 +128,7 @@ def test_no_such_function( create_res = create_lambda_function( func_name=function_name, handler_file=EHT.LAMBDA_FUNC_RAISE_EXCEPTION, - runtime="python3.9", + runtime=Runtime.python3_12, ) sfn_snapshot.add_transformer(RegexTransformer(function_name, "")) @@ -132,7 +161,7 @@ def test_no_such_function_catch( create_res = create_lambda_function( func_name=function_name, handler_file=EHT.LAMBDA_FUNC_RAISE_EXCEPTION, - runtime="python3.9", + runtime=Runtime.python3_12, ) sfn_snapshot.add_transformer(RegexTransformer(function_name, "")) diff --git a/tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.snapshot.json b/tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.snapshot.json index 402498ba8f1bd..b5271adfebb1e 100644 --- a/tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_raise_exception": { - "recorded-date": "22-06-2023, 13:27:25", + "recorded-date": "28-11-2024, 12:40:57", "recorded-content": { "get_execution_history": { "events": [ @@ -100,8 +100,155 @@ } } }, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_raise_custom_exception": { + "recorded-date": "28-11-2024, 12:41:13", + "recorded-content": { + "get_execution_history": { + "events": [ + { + "executionStartedEventDetails": { + "input": { + "FunctionName": "", + "Payload": null + }, + "inputDetails": { + "truncated": false + }, + "roleArn": "snf_role_arn" + }, + "id": 1, + "previousEventId": 0, + "timestamp": "timestamp", + "type": "ExecutionStarted" + }, + { + "id": 2, + "previousEventId": 0, + "stateEnteredEventDetails": { + "input": { + "FunctionName": "", + "Payload": null + }, + "inputDetails": { + "truncated": false + }, + "name": "InvokeLambda" + }, + "timestamp": "timestamp", + "type": "TaskStateEntered" + }, + { + "id": 3, + "lambdaFunctionScheduledEventDetails": { + "input": { + "FunctionName": "", + "Payload": null + }, + "inputDetails": { + "truncated": false + }, + "resource": "arn::lambda::111111111111:function:" + }, + "previousEventId": 2, + "timestamp": "timestamp", + "type": "LambdaFunctionScheduled" + }, + { + "id": 4, + "previousEventId": 3, + "timestamp": "timestamp", + "type": "LambdaFunctionStarted" + }, + { + "id": 5, + "lambdaFunctionFailedEventDetails": { + "cause": { + "errorMessage": "", + "errorType": "CustomException", + "requestId": "", + "stackTrace": [ + " File \"/var/task/handler.py\", line 9, in handler\n raise CustomException()\n" + ] + }, + "error": "CustomException" + }, + "previousEventId": 4, + "timestamp": "timestamp", + "type": "LambdaFunctionFailed" + }, + { + "id": 6, + "previousEventId": 5, + "stateExitedEventDetails": { + "name": "InvokeLambda", + "output": { + "Error": "CustomException", + "Cause": "{\"errorMessage\": \"\", \"errorType\": \"CustomException\", \"requestId\": \"\", \"stackTrace\": [\" File \\\"/var/task/handler.py\\\", line 9, in handler\\n raise CustomException()\\n\"]}" + }, + "outputDetails": { + "truncated": false + } + }, + "timestamp": "timestamp", + "type": "TaskStateExited" + }, + { + "id": 7, + "previousEventId": 6, + "stateEnteredEventDetails": { + "input": { + "Error": "CustomException", + "Cause": "{\"errorMessage\": \"\", \"errorType\": \"CustomException\", \"requestId\": \"\", \"stackTrace\": [\" File \\\"/var/task/handler.py\\\", line 9, in handler\\n raise CustomException()\\n\"]}" + }, + "inputDetails": { + "truncated": false + }, + "name": "ErrorMatched" + }, + "timestamp": "timestamp", + "type": "PassStateEntered" + }, + { + "id": 8, + "previousEventId": 7, + "stateExitedEventDetails": { + "name": "ErrorMatched", + "output": { + "Error": "CustomException", + "Cause": "{\"errorMessage\": \"\", \"errorType\": \"CustomException\", \"requestId\": \"\", \"stackTrace\": [\" File \\\"/var/task/handler.py\\\", line 9, in handler\\n raise CustomException()\\n\"]}" + }, + "outputDetails": { + "truncated": false + } + }, + "timestamp": "timestamp", + "type": "PassStateExited" + }, + { + "executionSucceededEventDetails": { + "output": { + "Error": "CustomException", + "Cause": "{\"errorMessage\": \"\", \"errorType\": \"CustomException\", \"requestId\": \"\", \"stackTrace\": [\" File \\\"/var/task/handler.py\\\", line 9, in handler\\n raise CustomException()\\n\"]}" + }, + "outputDetails": { + "truncated": false + } + }, + "id": 9, + "previousEventId": 8, + "timestamp": "timestamp", + "type": "ExecutionSucceeded" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_raise_exception_catch": { - "recorded-date": "22-06-2023, 13:27:43", + "recorded-date": "28-11-2024, 12:41:30", "recorded-content": { "get_execution_history": { "events": [ @@ -256,7 +403,7 @@ } }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_no_such_function": { - "recorded-date": "22-06-2023, 13:28:01", + "recorded-date": "28-11-2024, 12:41:47", "recorded-content": { "get_execution_history": { "events": [ @@ -357,7 +504,7 @@ } }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_no_such_function_catch": { - "recorded-date": "22-06-2023, 13:28:19", + "recorded-date": "28-11-2024, 12:42:04", "recorded-content": { "get_execution_history": { "events": [ diff --git a/tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.validation.json b/tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.validation.json index 1987674376b19..f4e6010ce6341 100644 --- a/tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.validation.json +++ b/tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.validation.json @@ -1,14 +1,17 @@ { "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_no_such_function": { - "last_validated_date": "2023-06-22T11:28:01+00:00" + "last_validated_date": "2024-11-28T12:41:47+00:00" }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_no_such_function_catch": { - "last_validated_date": "2023-06-22T11:28:19+00:00" + "last_validated_date": "2024-11-28T12:42:04+00:00" + }, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_raise_custom_exception": { + "last_validated_date": "2024-11-28T12:41:13+00:00" }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_raise_exception": { - "last_validated_date": "2023-06-22T11:27:25+00:00" + "last_validated_date": "2024-11-28T12:40:57+00:00" }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_raise_exception_catch": { - "last_validated_date": "2023-06-22T11:27:43+00:00" + "last_validated_date": "2024-11-28T12:41:30+00:00" } } diff --git a/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py b/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py index 13ce9adae510a..d91c7974919e9 100644 --- a/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py +++ b/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py @@ -17,7 +17,6 @@ ) -@markers.snapshot.skip_snapshot_verify(paths=["$..tracingConfiguration"]) class TestTaskServiceLambda: @markers.aws.validated def test_raise_exception( @@ -32,7 +31,7 @@ def test_raise_exception( create_lambda_function( func_name=function_name, handler_file=EHT.LAMBDA_FUNC_RAISE_EXCEPTION, - runtime="python3.9", + runtime=Runtime.python3_12, ) sfn_snapshot.add_transformer(RegexTransformer(function_name, "")) @@ -49,6 +48,37 @@ def test_raise_exception( exec_input, ) + @markers.aws.validated + def test_raise_custom_exception( + self, + aws_client, + create_iam_role_for_sfn, + create_state_machine, + create_lambda_function, + sfn_snapshot, + ): + function_name = f"lambda_func_{short_uid()}" + create_lambda_function( + func_name=function_name, + handler_file=EHT.LAMBDA_FUNC_RAISE_CUSTOM_EXCEPTION, + runtime=Runtime.python3_12, + ) + sfn_snapshot.add_transformer(RegexTransformer(function_name, "")) + + template = EHT.load_sfn_template(EHT.AWS_SERVICE_LAMBDA_INVOKE_CATCH_TBD) + template["States"]["InvokeLambda"]["Catch"][0]["ErrorEquals"].append("CustomException") + definition = json.dumps(template) + + exec_input = json.dumps({"FunctionName": function_name, "Payload": None}) + create_and_record_execution( + aws_client.stepfunctions, + create_iam_role_for_sfn, + create_state_machine, + sfn_snapshot, + definition, + exec_input, + ) + @markers.aws.validated def test_raise_exception_catch( self, @@ -62,7 +92,7 @@ def test_raise_exception_catch( create_lambda_function( func_name=function_name, handler_file=EHT.LAMBDA_FUNC_RAISE_EXCEPTION, - runtime="python3.9", + runtime=Runtime.python3_12, ) sfn_snapshot.add_transformer(RegexTransformer(function_name, "")) @@ -127,7 +157,7 @@ def test_no_such_function( create_lambda_function( func_name=function_name, handler_file=EHT.LAMBDA_FUNC_RAISE_EXCEPTION, - runtime="python3.9", + runtime=Runtime.python3_12, ) sfn_snapshot.add_transformer(RegexTransformer(function_name, "")) @@ -157,7 +187,7 @@ def test_no_such_function_catch( create_lambda_function( func_name=function_name, handler_file=EHT.LAMBDA_FUNC_RAISE_EXCEPTION, - runtime="python3.9", + runtime=Runtime.python3_12, ) sfn_snapshot.add_transformer(RegexTransformer(function_name, "")) @@ -187,7 +217,7 @@ def test_invoke_timeout( create_lambda_function( func_name=function_name, handler_file=TT.LAMBDA_WAIT_60_SECONDS, - runtime="python3.9", + runtime=Runtime.python3_12, ) sfn_snapshot.add_transformer(RegexTransformer(function_name, "")) diff --git a/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.snapshot.json b/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.snapshot.json index 47ca347fa81ee..33131f7120100 100644 --- a/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception": { - "recorded-date": "22-06-2023, 13:29:17", + "recorded-date": "28-11-2024, 13:03:36", "recorded-content": { "get_execution_history": { "events": [ @@ -105,15 +105,15 @@ } } }, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_no_such_function": { - "recorded-date": "22-06-2023, 13:29:54", + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_custom_exception": { + "recorded-date": "28-11-2024, 13:03:53", "recorded-content": { "get_execution_history": { "events": [ { "executionStartedEventDetails": { "input": { - "FunctionName": "no_such_", + "FunctionName": "", "Payload": null }, "inputDetails": { @@ -131,13 +131,13 @@ "previousEventId": 0, "stateEnteredEventDetails": { "input": { - "FunctionName": "no_such_", + "FunctionName": "", "Payload": null }, "inputDetails": { "truncated": false }, - "name": "Start" + "name": "InvokeLambda" }, "timestamp": "timestamp", "type": "TaskStateEntered" @@ -147,7 +147,7 @@ "previousEventId": 2, "taskScheduledEventDetails": { "parameters": { - "FunctionName": "no_such_", + "FunctionName": "", "Payload": null }, "region": "", @@ -171,8 +171,15 @@ "id": 5, "previousEventId": 4, "taskFailedEventDetails": { - "cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", - "error": "Lambda.ResourceNotFoundException", + "cause": { + "errorMessage": "", + "errorType": "CustomException", + "requestId": "", + "stackTrace": [ + " File \"/var/task/handler.py\", line 9, in handler\n raise CustomException()\n" + ] + }, + "error": "CustomException", "resource": "invoke", "resourceType": "lambda" }, @@ -180,14 +187,67 @@ "type": "TaskFailed" }, { - "executionFailedEventDetails": { - "cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", - "error": "Lambda.ResourceNotFoundException" - }, "id": 6, "previousEventId": 5, + "stateExitedEventDetails": { + "name": "InvokeLambda", + "output": { + "Error": "CustomException", + "Cause": "{\"errorMessage\":\"\",\"errorType\":\"CustomException\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 9, in handler\\n raise CustomException()\\n\"]}" + }, + "outputDetails": { + "truncated": false + } + }, "timestamp": "timestamp", - "type": "ExecutionFailed" + "type": "TaskStateExited" + }, + { + "id": 7, + "previousEventId": 6, + "stateEnteredEventDetails": { + "input": { + "Error": "CustomException", + "Cause": "{\"errorMessage\":\"\",\"errorType\":\"CustomException\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 9, in handler\\n raise CustomException()\\n\"]}" + }, + "inputDetails": { + "truncated": false + }, + "name": "ErrorMatched" + }, + "timestamp": "timestamp", + "type": "PassStateEntered" + }, + { + "id": 8, + "previousEventId": 7, + "stateExitedEventDetails": { + "name": "ErrorMatched", + "output": { + "Error": "CustomException", + "Cause": "{\"errorMessage\":\"\",\"errorType\":\"CustomException\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 9, in handler\\n raise CustomException()\\n\"]}" + }, + "outputDetails": { + "truncated": false + } + }, + "timestamp": "timestamp", + "type": "PassStateExited" + }, + { + "executionSucceededEventDetails": { + "output": { + "Error": "CustomException", + "Cause": "{\"errorMessage\":\"\",\"errorType\":\"CustomException\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 9, in handler\\n raise CustomException()\\n\"]}" + }, + "outputDetails": { + "truncated": false + } + }, + "id": 9, + "previousEventId": 8, + "timestamp": "timestamp", + "type": "ExecutionSucceeded" } ], "ResponseMetadata": { @@ -198,7 +258,7 @@ } }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch": { - "recorded-date": "22-06-2023, 13:29:36", + "recorded-date": "28-11-2024, 13:04:09", "recorded-content": { "get_execution_history": { "events": [ @@ -357,16 +417,18 @@ } } }, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_no_such_function_catch": { - "recorded-date": "22-06-2023, 13:30:13", + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch_output_path[None]": { + "recorded-date": "28-11-2024, 13:08:15", "recorded-content": { "get_execution_history": { "events": [ { "executionStartedEventDetails": { "input": { - "FunctionName": "no_such_", - "Payload": null + "FunctionName": "lambda_function_name", + "Payload": { + "payload_input_value_0": 0 + } }, "inputDetails": { "truncated": false @@ -383,13 +445,15 @@ "previousEventId": 0, "stateEnteredEventDetails": { "input": { - "FunctionName": "no_such_", - "Payload": null + "FunctionName": "lambda_function_name", + "Payload": { + "payload_input_value_0": 0 + } }, "inputDetails": { "truncated": false }, - "name": "Start" + "name": "InvokeLambda" }, "timestamp": "timestamp", "type": "TaskStateEntered" @@ -399,8 +463,10 @@ "previousEventId": 2, "taskScheduledEventDetails": { "parameters": { - "FunctionName": "no_such_", - "Payload": null + "FunctionName": "lambda_function_name", + "Payload": { + "payload_input_value_0": 0 + } }, "region": "", "resource": "invoke", @@ -423,8 +489,15 @@ "id": 5, "previousEventId": 4, "taskFailedEventDetails": { - "cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", - "error": "Lambda.ResourceNotFoundException", + "cause": { + "errorMessage": "Some exception was raised.", + "errorType": "Exception", + "requestId": "", + "stackTrace": [ + " File \"/var/task/handler.py\", line 2, in handler\n raise Exception(\"Some exception was raised.\")\n" + ] + }, + "error": "Exception", "resource": "invoke", "resourceType": "lambda" }, @@ -435,10 +508,10 @@ "id": 6, "previousEventId": 5, "stateExitedEventDetails": { - "name": "Start", + "name": "InvokeLambda", "output": { - "Error": "Lambda.ResourceNotFoundException", - "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" + "Error": "Exception", + "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" }, "outputDetails": { "truncated": false @@ -452,13 +525,13 @@ "previousEventId": 6, "stateEnteredEventDetails": { "input": { - "Error": "Lambda.ResourceNotFoundException", - "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" + "Error": "Exception", + "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" }, "inputDetails": { "truncated": false }, - "name": "EndWithStateTaskFailedHandler" + "name": "HandleGeneralError" }, "timestamp": "timestamp", "type": "PassStateEntered" @@ -467,13 +540,11 @@ "id": 8, "previousEventId": 7, "stateExitedEventDetails": { - "name": "EndWithStateTaskFailedHandler", + "name": "HandleGeneralError", "output": { - "Error": "Lambda.ResourceNotFoundException", - "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", - "task_failed_error": { - "Error": "Lambda.ResourceNotFoundException", - "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" + "InputValue": { + "Error": "Exception", + "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" } }, "outputDetails": { @@ -486,11 +557,9 @@ { "executionSucceededEventDetails": { "output": { - "Error": "Lambda.ResourceNotFoundException", - "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", - "task_failed_error": { - "Error": "Lambda.ResourceNotFoundException", - "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" + "InputValue": { + "Error": "Exception", + "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" } }, "outputDetails": { @@ -510,16 +579,18 @@ } } }, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_invoke_timeout": { - "recorded-date": "10-03-2024, 16:41:35", + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch_output_path[$.Payload]": { + "recorded-date": "28-11-2024, 13:08:26", "recorded-content": { "get_execution_history": { "events": [ { "executionStartedEventDetails": { "input": { - "FunctionName": "", - "Payload": null + "FunctionName": "lambda_function_name", + "Payload": { + "payload_input_value_0": 0 + } }, "inputDetails": { "truncated": false @@ -536,13 +607,15 @@ "previousEventId": 0, "stateEnteredEventDetails": { "input": { - "FunctionName": "", - "Payload": null + "FunctionName": "lambda_function_name", + "Payload": { + "payload_input_value_0": 0 + } }, "inputDetails": { "truncated": false }, - "name": "Start" + "name": "InvokeLambda" }, "timestamp": "timestamp", "type": "TaskStateEntered" @@ -552,13 +625,14 @@ "previousEventId": 2, "taskScheduledEventDetails": { "parameters": { - "FunctionName": "", - "Payload": null + "FunctionName": "lambda_function_name", + "Payload": { + "payload_input_value_0": 0 + } }, "region": "", "resource": "invoke", - "resourceType": "lambda", - "timeoutInSeconds": 5 + "resourceType": "lambda" }, "timestamp": "timestamp", "type": "TaskScheduled" @@ -576,22 +650,30 @@ { "id": 5, "previousEventId": 4, - "taskTimedOutEventDetails": { - "error": "States.Timeout", + "taskFailedEventDetails": { + "cause": { + "errorMessage": "Some exception was raised.", + "errorType": "Exception", + "requestId": "", + "stackTrace": [ + " File \"/var/task/handler.py\", line 2, in handler\n raise Exception(\"Some exception was raised.\")\n" + ] + }, + "error": "Exception", "resource": "invoke", "resourceType": "lambda" }, "timestamp": "timestamp", - "type": "TaskTimedOut" + "type": "TaskFailed" }, { "id": 6, "previousEventId": 5, "stateExitedEventDetails": { - "name": "Start", + "name": "InvokeLambda", "output": { - "Error": "States.Timeout", - "Cause": "" + "Error": "Exception", + "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" }, "outputDetails": { "truncated": false @@ -605,13 +687,13 @@ "previousEventId": 6, "stateEnteredEventDetails": { "input": { - "Error": "States.Timeout", - "Cause": "" + "Error": "Exception", + "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" }, "inputDetails": { "truncated": false }, - "name": "EndWithHandler" + "name": "HandleGeneralError" }, "timestamp": "timestamp", "type": "PassStateEntered" @@ -620,13 +702,11 @@ "id": 8, "previousEventId": 7, "stateExitedEventDetails": { - "name": "EndWithHandler", + "name": "HandleGeneralError", "output": { - "Error": "States.Timeout", - "Cause": "", - "error": { - "Error": "States.Timeout", - "Cause": "" + "InputValue": { + "Error": "Exception", + "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" } }, "outputDetails": { @@ -639,11 +719,9 @@ { "executionSucceededEventDetails": { "output": { - "Error": "States.Timeout", - "Cause": "", - "error": { - "Error": "States.Timeout", - "Cause": "" + "InputValue": { + "Error": "Exception", + "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" } }, "outputDetails": { @@ -663,8 +741,8 @@ } } }, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch_output_path[None]": { - "recorded-date": "20-09-2024, 15:50:50", + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch_output_path[$.no.such.path]": { + "recorded-date": "28-11-2024, 13:08:43", "recorded-content": { "get_execution_history": { "events": [ @@ -825,18 +903,16 @@ } } }, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch_output_path[$.Payload]": { - "recorded-date": "20-09-2024, 15:51:07", + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_no_such_function": { + "recorded-date": "28-11-2024, 13:05:16", "recorded-content": { "get_execution_history": { "events": [ { "executionStartedEventDetails": { "input": { - "FunctionName": "lambda_function_name", - "Payload": { - "payload_input_value_0": 0 - } + "FunctionName": "no_such_", + "Payload": null }, "inputDetails": { "truncated": false @@ -853,15 +929,13 @@ "previousEventId": 0, "stateEnteredEventDetails": { "input": { - "FunctionName": "lambda_function_name", - "Payload": { - "payload_input_value_0": 0 - } + "FunctionName": "no_such_", + "Payload": null }, "inputDetails": { "truncated": false }, - "name": "InvokeLambda" + "name": "Start" }, "timestamp": "timestamp", "type": "TaskStateEntered" @@ -871,10 +945,8 @@ "previousEventId": 2, "taskScheduledEventDetails": { "parameters": { - "FunctionName": "lambda_function_name", - "Payload": { - "payload_input_value_0": 0 - } + "FunctionName": "no_such_", + "Payload": null }, "region": "", "resource": "invoke", @@ -897,15 +969,100 @@ "id": 5, "previousEventId": 4, "taskFailedEventDetails": { - "cause": { - "errorMessage": "Some exception was raised.", - "errorType": "Exception", - "requestId": "", - "stackTrace": [ - " File \"/var/task/handler.py\", line 2, in handler\n raise Exception(\"Some exception was raised.\")\n" - ] + "cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", + "error": "Lambda.ResourceNotFoundException", + "resource": "invoke", + "resourceType": "lambda" + }, + "timestamp": "timestamp", + "type": "TaskFailed" + }, + { + "executionFailedEventDetails": { + "cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", + "error": "Lambda.ResourceNotFoundException" + }, + "id": 6, + "previousEventId": 5, + "timestamp": "timestamp", + "type": "ExecutionFailed" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_no_such_function_catch": { + "recorded-date": "28-11-2024, 13:05:33", + "recorded-content": { + "get_execution_history": { + "events": [ + { + "executionStartedEventDetails": { + "input": { + "FunctionName": "no_such_", + "Payload": null }, - "error": "Exception", + "inputDetails": { + "truncated": false + }, + "roleArn": "snf_role_arn" + }, + "id": 1, + "previousEventId": 0, + "timestamp": "timestamp", + "type": "ExecutionStarted" + }, + { + "id": 2, + "previousEventId": 0, + "stateEnteredEventDetails": { + "input": { + "FunctionName": "no_such_", + "Payload": null + }, + "inputDetails": { + "truncated": false + }, + "name": "Start" + }, + "timestamp": "timestamp", + "type": "TaskStateEntered" + }, + { + "id": 3, + "previousEventId": 2, + "taskScheduledEventDetails": { + "parameters": { + "FunctionName": "no_such_", + "Payload": null + }, + "region": "", + "resource": "invoke", + "resourceType": "lambda" + }, + "timestamp": "timestamp", + "type": "TaskScheduled" + }, + { + "id": 4, + "previousEventId": 3, + "taskStartedEventDetails": { + "resource": "invoke", + "resourceType": "lambda" + }, + "timestamp": "timestamp", + "type": "TaskStarted" + }, + { + "id": 5, + "previousEventId": 4, + "taskFailedEventDetails": { + "cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", + "error": "Lambda.ResourceNotFoundException", "resource": "invoke", "resourceType": "lambda" }, @@ -916,10 +1073,10 @@ "id": 6, "previousEventId": 5, "stateExitedEventDetails": { - "name": "InvokeLambda", + "name": "Start", "output": { - "Error": "Exception", - "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" + "Error": "Lambda.ResourceNotFoundException", + "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" }, "outputDetails": { "truncated": false @@ -933,13 +1090,13 @@ "previousEventId": 6, "stateEnteredEventDetails": { "input": { - "Error": "Exception", - "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" + "Error": "Lambda.ResourceNotFoundException", + "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" }, "inputDetails": { "truncated": false }, - "name": "HandleGeneralError" + "name": "EndWithStateTaskFailedHandler" }, "timestamp": "timestamp", "type": "PassStateEntered" @@ -948,11 +1105,13 @@ "id": 8, "previousEventId": 7, "stateExitedEventDetails": { - "name": "HandleGeneralError", + "name": "EndWithStateTaskFailedHandler", "output": { - "InputValue": { - "Error": "Exception", - "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" + "Error": "Lambda.ResourceNotFoundException", + "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", + "task_failed_error": { + "Error": "Lambda.ResourceNotFoundException", + "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" } }, "outputDetails": { @@ -965,9 +1124,11 @@ { "executionSucceededEventDetails": { "output": { - "InputValue": { - "Error": "Exception", - "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" + "Error": "Lambda.ResourceNotFoundException", + "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", + "task_failed_error": { + "Error": "Lambda.ResourceNotFoundException", + "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" } }, "outputDetails": { @@ -987,18 +1148,16 @@ } } }, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch_output_path[$.no.such.path]": { - "recorded-date": "20-09-2024, 15:51:29", + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_invoke_timeout": { + "recorded-date": "28-11-2024, 13:05:54", "recorded-content": { "get_execution_history": { "events": [ { "executionStartedEventDetails": { "input": { - "FunctionName": "lambda_function_name", - "Payload": { - "payload_input_value_0": 0 - } + "FunctionName": "", + "Payload": null }, "inputDetails": { "truncated": false @@ -1015,15 +1174,13 @@ "previousEventId": 0, "stateEnteredEventDetails": { "input": { - "FunctionName": "lambda_function_name", - "Payload": { - "payload_input_value_0": 0 - } + "FunctionName": "", + "Payload": null }, "inputDetails": { "truncated": false }, - "name": "InvokeLambda" + "name": "Start" }, "timestamp": "timestamp", "type": "TaskStateEntered" @@ -1033,14 +1190,13 @@ "previousEventId": 2, "taskScheduledEventDetails": { "parameters": { - "FunctionName": "lambda_function_name", - "Payload": { - "payload_input_value_0": 0 - } + "FunctionName": "", + "Payload": null }, "region": "", "resource": "invoke", - "resourceType": "lambda" + "resourceType": "lambda", + "timeoutInSeconds": 5 }, "timestamp": "timestamp", "type": "TaskScheduled" @@ -1058,30 +1214,22 @@ { "id": 5, "previousEventId": 4, - "taskFailedEventDetails": { - "cause": { - "errorMessage": "Some exception was raised.", - "errorType": "Exception", - "requestId": "", - "stackTrace": [ - " File \"/var/task/handler.py\", line 2, in handler\n raise Exception(\"Some exception was raised.\")\n" - ] - }, - "error": "Exception", + "taskTimedOutEventDetails": { + "error": "States.Timeout", "resource": "invoke", "resourceType": "lambda" }, "timestamp": "timestamp", - "type": "TaskFailed" + "type": "TaskTimedOut" }, { "id": 6, "previousEventId": 5, "stateExitedEventDetails": { - "name": "InvokeLambda", + "name": "Start", "output": { - "Error": "Exception", - "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" + "Error": "States.Timeout", + "Cause": "" }, "outputDetails": { "truncated": false @@ -1095,13 +1243,13 @@ "previousEventId": 6, "stateEnteredEventDetails": { "input": { - "Error": "Exception", - "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" + "Error": "States.Timeout", + "Cause": "" }, "inputDetails": { "truncated": false }, - "name": "HandleGeneralError" + "name": "EndWithHandler" }, "timestamp": "timestamp", "type": "PassStateEntered" @@ -1110,11 +1258,13 @@ "id": 8, "previousEventId": 7, "stateExitedEventDetails": { - "name": "HandleGeneralError", + "name": "EndWithHandler", "output": { - "InputValue": { - "Error": "Exception", - "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" + "Error": "States.Timeout", + "Cause": "", + "error": { + "Error": "States.Timeout", + "Cause": "" } }, "outputDetails": { @@ -1127,9 +1277,11 @@ { "executionSucceededEventDetails": { "output": { - "InputValue": { - "Error": "Exception", - "Cause": "{\"errorMessage\":\"Some exception was raised.\",\"errorType\":\"Exception\",\"requestId\":\"\",\"stackTrace\":[\" File \\\"/var/task/handler.py\\\", line 2, in handler\\n raise Exception(\\\"Some exception was raised.\\\")\\n\"]}" + "Error": "States.Timeout", + "Cause": "", + "error": { + "Error": "States.Timeout", + "Cause": "" } }, "outputDetails": { diff --git a/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.validation.json b/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.validation.json index b7a43b1af14ea..8d7be471fc48c 100644 --- a/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.validation.json +++ b/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.validation.json @@ -1,26 +1,29 @@ { "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_invoke_timeout": { - "last_validated_date": "2024-03-10T16:41:35+00:00" + "last_validated_date": "2024-11-28T13:05:54+00:00" }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_no_such_function": { - "last_validated_date": "2023-06-22T11:29:54+00:00" + "last_validated_date": "2024-11-28T13:05:16+00:00" }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_no_such_function_catch": { - "last_validated_date": "2023-06-22T11:30:13+00:00" + "last_validated_date": "2024-11-28T13:05:33+00:00" + }, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_custom_exception": { + "last_validated_date": "2024-11-28T13:03:53+00:00" }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception": { - "last_validated_date": "2023-06-22T11:29:17+00:00" + "last_validated_date": "2024-11-28T13:03:36+00:00" }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch": { - "last_validated_date": "2023-06-22T11:29:36+00:00" + "last_validated_date": "2024-11-28T13:04:09+00:00" }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch_output_path[$.Payload]": { - "last_validated_date": "2024-09-20T15:51:07+00:00" + "last_validated_date": "2024-11-28T13:08:26+00:00" }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch_output_path[$.no.such.path]": { - "last_validated_date": "2024-09-20T15:51:29+00:00" + "last_validated_date": "2024-11-28T13:08:43+00:00" }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch_output_path[None]": { - "last_validated_date": "2024-09-20T15:50:50+00:00" + "last_validated_date": "2024-11-28T13:08:15+00:00" } } From a47e701ac2b19cadffb1b62eaa54e347c29a0b35 Mon Sep 17 00:00:00 2001 From: Zain Zafar Date: Fri, 29 Nov 2024 12:14:17 +0000 Subject: [PATCH 30/38] Added test and fix for wrong time format and serialization in events v2 (#11959) --- .../localstack/aws/api/events/__init__.py | 2 +- .../localstack/services/events/utils.py | 5 +- tests/aws/services/events/test_events.py | 64 +++++++++++++++++++ .../services/events/test_events.snapshot.json | 37 +++++++++++ .../events/test_events.validation.json | 3 + 5 files changed, 109 insertions(+), 2 deletions(-) diff --git a/localstack-core/localstack/aws/api/events/__init__.py b/localstack-core/localstack/aws/api/events/__init__.py index b1f621adb398f..5fd1845841a0b 100644 --- a/localstack-core/localstack/aws/api/events/__init__.py +++ b/localstack-core/localstack/aws/api/events/__init__.py @@ -919,7 +919,7 @@ class EventSource(TypedDict, total=False): EventSourceList = List[EventSource] -EventTime = datetime +EventTime = datetime | str HeaderParametersMap = Dict[HeaderKey, HeaderValue] QueryStringParametersMap = Dict[QueryStringKey, QueryStringValue] PathParameterList = List[PathParameter] diff --git a/localstack-core/localstack/services/events/utils.py b/localstack-core/localstack/services/events/utils.py index fa263c35f62b1..3dff68e157ebf 100644 --- a/localstack-core/localstack/services/events/utils.py +++ b/localstack-core/localstack/services/events/utils.py @@ -181,6 +181,9 @@ def format_event( message_id = message.get("original_id", str(long_uid())) region = message.get("original_region", region) account_id = message.get("original_account", account_id) + # Format the datetime to ISO-8601 string + event_time = get_event_time(event) + formatted_time = event_time_to_time_string(event_time) formatted_event = { "version": "0", @@ -188,7 +191,7 @@ def format_event( "detail-type": event.get("DetailType"), "source": event.get("Source"), "account": account_id, - "time": get_event_time(event), + "time": formatted_time, "region": region, "resources": event.get("Resources", []), "detail": json.loads(event.get("Detail", "{}")), diff --git a/tests/aws/services/events/test_events.py b/tests/aws/services/events/test_events.py index fbe59dc980490..35f0aa7696e89 100644 --- a/tests/aws/services/events/test_events.py +++ b/tests/aws/services/events/test_events.py @@ -3,8 +3,10 @@ """ import base64 +import datetime import json import os +import re import time import uuid @@ -578,6 +580,68 @@ def test_put_events_with_target_delivery_failure( assert len(messages) == 0, "No messages should be delivered when queue doesn't exist" + @markers.aws.validated + @pytest.mark.skipif(is_old_provider(), reason="Test specific for v2 provider") + def test_put_events_with_time_field( + self, events_put_rule, create_sqs_events_target, aws_client, snapshot + ): + """Test that EventBridge correctly handles datetime serialization in events.""" + rule_name = f"test-rule-{short_uid()}" + queue_url, queue_arn = create_sqs_events_target() + + snapshot.add_transformers_list( + [ + snapshot.transform.key_value("MD5OfBody", reference_replacement=False), + *snapshot.transform.sqs_api(), + ] + ) + + events_put_rule( + Name=rule_name, + EventPattern=json.dumps( + {"source": ["test-source"], "detail-type": ["test-detail-type"]} + ), + ) + + aws_client.events.put_targets(Rule=rule_name, Targets=[{"Id": "id1", "Arn": queue_arn}]) + + timestamp = datetime.datetime.utcnow() + event = { + "Source": "test-source", + "DetailType": "test-detail-type", + "Time": timestamp, + "Detail": json.dumps({"message": "test message"}), + } + + response = aws_client.events.put_events(Entries=[event]) + snapshot.match("put-events", response) + + messages = sqs_collect_messages(aws_client, queue_url, expected_events_count=1) + assert len(messages) == 1 + snapshot.match("sqs-messages", messages) + + received_event = json.loads(messages[0]["Body"]) + # Explicit assertions for time field format GH issue: https://github.com/localstack/localstack/issues/11630#issuecomment-2506187279 + assert "time" in received_event, "Time field missing in the event" + time_str = received_event["time"] + + # Verify ISO8601 format: YYYY-MM-DDThh:mm:ssZ + # Example: "2024-11-28T13:44:36Z" + assert re.match( + r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$", time_str + ), f"Time field '{time_str}' does not match ISO8601 format (YYYY-MM-DDThh:mm:ssZ)" + + # Verify we can parse it back to datetime + datetime_obj = datetime.datetime.strptime(time_str, "%Y-%m-%dT%H:%M:%SZ") + assert isinstance( + datetime_obj, datetime.datetime + ), f"Failed to parse time string '{time_str}' back to datetime object" + + time_difference = abs((datetime_obj - timestamp.replace(microsecond=0)).total_seconds()) + assert ( + time_difference <= 60 + ), f"Time in event '{time_str}' differs too much from sent time '{timestamp.isoformat()}'" + class TestEventBus: @markers.aws.validated diff --git a/tests/aws/services/events/test_events.snapshot.json b/tests/aws/services/events/test_events.snapshot.json index c5c841f9cfad8..3df20f8468b1c 100644 --- a/tests/aws/services/events/test_events.snapshot.json +++ b/tests/aws/services/events/test_events.snapshot.json @@ -2695,5 +2695,42 @@ } } } + }, + "tests/aws/services/events/test_events.py::TestEvents::test_put_events_with_time_field": { + "recorded-date": "28-11-2024, 21:25:00", + "recorded-content": { + "put-events": { + "Entries": [ + { + "EventId": "" + } + ], + "FailedEntryCount": 0, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "sqs-messages": [ + { + "MessageId": "", + "ReceiptHandle": "", + "MD5OfBody": "m-d5-of-body", + "Body": { + "version": "0", + "id": "", + "detail-type": "test-detail-type", + "source": "test-source", + "account": "111111111111", + "time": "date", + "region": "", + "resources": [], + "detail": { + "message": "test message" + } + } + } + ] + } } } diff --git a/tests/aws/services/events/test_events.validation.json b/tests/aws/services/events/test_events.validation.json index 95d3f89a3cf9b..7adc430877f4e 100644 --- a/tests/aws/services/events/test_events.validation.json +++ b/tests/aws/services/events/test_events.validation.json @@ -188,6 +188,9 @@ "tests/aws/services/events/test_events.py::TestEvents::test_put_events_with_target_delivery_failure": { "last_validated_date": "2024-11-20T17:19:19+00:00" }, + "tests/aws/services/events/test_events.py::TestEvents::test_put_events_with_time_field": { + "last_validated_date": "2024-11-28T21:25:00+00:00" + }, "tests/aws/services/events/test_events.py::TestEvents::test_put_events_without_source": { "last_validated_date": "2024-06-19T10:40:50+00:00" } From 365d9ad52300ea901fd32250be129d675577ad38 Mon Sep 17 00:00:00 2001 From: MEPalma <64580864+MEPalma@users.noreply.github.com> Date: Fri, 29 Nov 2024 15:25:00 +0100 Subject: [PATCH 31/38] StepFunctions: Support for ContextObject Paths Bindings for ErrorPath and CausePath (#11958) --- .../stepfunctions/asl/antlr/ASLParser.g4 | 14 +- .../asl/antlr/runtime/ASLParser.py | 2045 +++++++++-------- .../asl/antlr/runtime/ASLParserListener.py | 18 + .../asl/antlr/runtime/ASLParserVisitor.py | 10 + .../component/state/state_fail/cause_decl.py | 7 + .../component/state/state_fail/error_decl.py | 7 + .../stepfunctions/asl/parse/preprocessor.py | 22 + .../context_object_templates.py | 3 + .../context_object_error_cause_path.json5 | 10 + .../v2/context_object/test_context_object.py | 11 +- .../test_context_object.snapshot.json | 49 + .../test_context_object.validation.json | 3 + 12 files changed, 1203 insertions(+), 996 deletions(-) create mode 100644 tests/aws/services/stepfunctions/templates/context_object/statemachines/context_object_error_cause_path.json5 diff --git a/localstack-core/localstack/services/stepfunctions/asl/antlr/ASLParser.g4 b/localstack-core/localstack/services/stepfunctions/asl/antlr/ASLParser.g4 index 3fe2b09564dce..2cc3d09e048d2 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/antlr/ASLParser.g4 +++ b/localstack-core/localstack/services/stepfunctions/asl/antlr/ASLParser.g4 @@ -120,9 +120,10 @@ error_decl: ; error_path_decl: - ERRORPATH COLON variable_sample # error_path_decl_var - | ERRORPATH COLON STRINGPATH # error_path_decl_path - | ERRORPATH COLON STRINGINTRINSICFUNC # error_path_decl_intrinsic + ERRORPATH COLON variable_sample # error_path_decl_var + | ERRORPATH COLON STRINGPATH # error_path_decl_path + | ERRORPATH COLON STRINGPATHCONTEXTOBJ # error_path_decl_context + | ERRORPATH COLON STRINGINTRINSICFUNC # error_path_decl_intrinsic ; cause_decl: @@ -131,9 +132,10 @@ cause_decl: ; cause_path_decl: - CAUSEPATH COLON variable_sample # cause_path_decl_var - | CAUSEPATH COLON STRINGPATH # cause_path_decl_path - | CAUSEPATH COLON STRINGINTRINSICFUNC # cause_path_decl_intrinsic + CAUSEPATH COLON variable_sample # cause_path_decl_var + | CAUSEPATH COLON STRINGPATH # cause_path_decl_path + | CAUSEPATH COLON STRINGPATHCONTEXTOBJ # cause_path_decl_context + | CAUSEPATH COLON STRINGINTRINSICFUNC # cause_path_decl_intrinsic ; seconds_decl: SECONDS COLON STRINGJSONATA # seconds_jsonata | SECONDS COLON INT # seconds_int; diff --git a/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParser.py b/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParser.py index 22386a4edcce7..838f50e6b88cd 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParser.py +++ b/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParser.py @@ -10,7 +10,7 @@ def serializedATN(): return [ - 4,1,160,1229,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6, + 4,1,160,1235,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6, 7,6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,13,7, 13,2,14,7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,19,2, 20,7,20,2,21,7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,2,26,7, @@ -42,117 +42,117 @@ def serializedATN(): 16,1,16,1,17,1,17,1,17,1,17,3,17,388,8,17,1,18,1,18,1,18,1,18,1, 18,1,18,1,18,1,18,1,18,1,18,3,18,400,8,18,3,18,402,8,18,1,19,1,19, 1,19,1,19,1,20,1,20,1,20,1,20,1,21,1,21,1,21,1,21,1,21,1,21,3,21, - 418,8,21,1,22,1,22,1,22,1,22,1,22,1,22,1,22,1,22,1,22,3,22,429,8, - 22,1,23,1,23,1,23,1,23,1,23,1,23,3,23,437,8,23,1,24,1,24,1,24,1, - 24,1,24,1,24,1,24,1,24,1,24,3,24,448,8,24,1,25,1,25,1,25,1,25,1, - 25,1,25,3,25,456,8,25,1,26,1,26,1,26,1,26,1,26,1,26,3,26,464,8,26, - 1,27,1,27,1,27,1,27,1,27,1,27,3,27,472,8,27,1,28,1,28,1,28,1,28, - 1,28,1,28,3,28,480,8,28,1,29,1,29,1,29,1,29,1,29,1,29,3,29,488,8, - 29,1,30,1,30,1,30,1,30,1,30,1,30,1,30,1,30,1,30,3,30,499,8,30,1, - 31,1,31,1,31,1,31,1,31,1,31,3,31,507,8,31,1,32,1,32,1,32,1,32,1, - 32,1,32,3,32,515,8,32,1,33,1,33,1,33,1,33,1,34,1,34,1,34,1,34,1, - 35,1,35,1,35,1,35,1,35,1,35,3,35,531,8,35,1,36,1,36,1,36,1,36,1, - 36,1,36,3,36,539,8,36,1,37,1,37,1,37,1,37,1,37,1,37,3,37,547,8,37, - 1,38,1,38,1,38,1,38,1,38,1,38,3,38,555,8,38,1,39,1,39,1,40,1,40, - 1,40,1,40,5,40,563,8,40,10,40,12,40,566,9,40,1,40,1,40,1,40,1,40, - 3,40,572,8,40,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,41, - 1,41,1,41,1,41,1,41,1,41,1,41,3,41,590,8,41,1,42,1,42,1,42,1,42, - 5,42,596,8,42,10,42,12,42,599,9,42,1,42,1,42,1,42,1,42,3,42,605, - 8,42,1,43,1,43,1,43,3,43,610,8,43,1,44,1,44,1,44,1,44,1,44,3,44, - 617,8,44,1,45,1,45,1,45,1,45,1,46,1,46,1,46,1,46,1,46,1,46,5,46, - 629,8,46,10,46,12,46,632,9,46,1,46,1,46,3,46,636,8,46,1,47,1,47, - 1,48,1,48,1,48,1,48,1,48,1,48,5,48,646,8,48,10,48,12,48,649,9,48, - 1,48,1,48,3,48,653,8,48,1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,49, - 1,49,1,49,1,49,1,49,1,49,1,49,1,49,3,49,670,8,49,1,50,1,50,1,50, - 3,50,675,8,50,1,51,1,51,1,51,1,51,1,51,1,51,5,51,683,8,51,10,51, - 12,51,686,9,51,1,51,1,51,3,51,690,8,51,1,52,1,52,1,52,1,52,1,52, - 1,52,3,52,698,8,52,1,53,1,53,1,53,1,53,1,53,1,53,3,53,706,8,53,1, - 54,1,54,1,54,1,54,1,55,1,55,1,55,1,55,1,55,1,55,5,55,718,8,55,10, - 55,12,55,721,9,55,1,55,1,55,3,55,725,8,55,1,56,1,56,1,56,1,56,1, - 57,1,57,1,57,3,57,734,8,57,1,58,1,58,1,58,1,58,1,58,1,58,5,58,742, - 8,58,10,58,12,58,745,9,58,1,58,1,58,3,58,749,8,58,1,59,1,59,1,59, - 1,59,1,59,1,59,3,59,757,8,59,1,60,1,60,1,60,1,60,1,61,1,61,1,62, - 1,62,1,62,1,62,1,62,1,62,5,62,771,8,62,10,62,12,62,774,9,62,1,62, - 1,62,1,63,1,63,1,63,1,63,4,63,782,8,63,11,63,12,63,783,1,63,1,63, - 1,63,1,63,1,63,1,63,5,63,792,8,63,10,63,12,63,795,9,63,1,63,1,63, - 3,63,799,8,63,1,64,1,64,1,64,1,64,1,64,3,64,806,8,64,1,65,1,65,1, - 65,1,65,3,65,812,8,65,1,66,1,66,1,66,1,66,1,66,1,66,1,66,5,66,821, - 8,66,10,66,12,66,824,9,66,1,66,1,66,3,66,828,8,66,1,67,1,67,1,67, - 1,67,1,67,1,67,1,67,1,67,1,67,3,67,839,8,67,1,68,1,68,1,68,1,68, - 1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,3,68,855,8,68, - 1,69,1,69,1,69,1,69,1,69,1,69,5,69,863,8,69,10,69,12,69,866,9,69, - 1,69,1,69,1,70,1,70,1,70,1,70,1,70,1,70,5,70,876,8,70,10,70,12,70, - 879,9,70,1,70,1,70,1,71,1,71,1,71,1,71,3,71,887,8,71,1,72,1,72,1, - 72,1,72,1,72,1,72,5,72,895,8,72,10,72,12,72,898,9,72,1,72,1,72,1, - 73,1,73,3,73,904,8,73,1,74,1,74,1,74,1,74,1,75,1,75,1,76,1,76,1, - 76,1,76,1,77,1,77,1,78,1,78,1,78,1,78,1,78,1,78,5,78,924,8,78,10, - 78,12,78,927,9,78,1,78,1,78,1,79,1,79,1,79,1,79,3,79,935,8,79,1, - 80,1,80,1,80,1,80,1,81,1,81,1,81,1,81,1,81,1,81,5,81,947,8,81,10, - 81,12,81,950,9,81,1,81,1,81,1,82,1,82,1,82,1,82,3,82,958,8,82,1, - 83,1,83,1,83,1,83,1,83,1,83,5,83,966,8,83,10,83,12,83,969,9,83,1, - 83,1,83,1,84,1,84,1,84,1,84,1,84,3,84,978,8,84,1,85,1,85,1,85,1, - 85,1,86,1,86,1,86,1,86,1,87,1,87,1,87,1,87,1,87,1,87,5,87,994,8, - 87,10,87,12,87,997,9,87,1,87,1,87,1,88,1,88,1,88,1,88,1,88,1,88, - 3,88,1007,8,88,1,89,1,89,1,89,1,89,1,89,1,89,3,89,1015,8,89,1,90, - 1,90,1,90,1,90,1,90,1,90,3,90,1023,8,90,1,91,1,91,1,91,1,91,1,91, - 1,91,3,91,1031,8,91,1,92,1,92,1,92,1,92,1,92,1,92,3,92,1039,8,92, - 1,93,1,93,1,93,1,93,1,93,1,93,3,93,1047,8,93,1,94,1,94,1,94,1,94, - 1,95,1,95,1,95,1,95,1,95,1,95,5,95,1059,8,95,10,95,12,95,1062,9, - 95,1,95,1,95,1,96,1,96,3,96,1068,8,96,1,97,1,97,1,97,1,97,1,97,1, - 97,5,97,1076,8,97,10,97,12,97,1079,9,97,3,97,1081,8,97,1,97,1,97, - 1,98,1,98,1,98,1,98,5,98,1089,8,98,10,98,12,98,1092,9,98,1,98,1, - 98,1,99,1,99,1,99,1,99,1,99,1,99,1,99,3,99,1103,8,99,1,100,1,100, - 1,100,1,100,1,100,1,100,5,100,1111,8,100,10,100,12,100,1114,9,100, - 1,100,1,100,1,101,1,101,1,101,1,101,1,102,1,102,1,102,1,102,1,103, - 1,103,1,103,1,103,1,104,1,104,1,104,1,104,1,105,1,105,1,105,1,105, - 1,106,1,106,1,106,1,106,1,106,1,106,5,106,1144,8,106,10,106,12,106, - 1147,9,106,3,106,1149,8,106,1,106,1,106,1,107,1,107,1,107,1,107, - 5,107,1157,8,107,10,107,12,107,1160,9,107,1,107,1,107,1,108,1,108, - 1,108,1,108,1,108,1,108,3,108,1170,8,108,1,109,1,109,1,110,1,110, - 1,111,1,111,1,112,1,112,3,112,1180,8,112,1,113,1,113,1,113,1,113, - 5,113,1186,8,113,10,113,12,113,1189,9,113,1,113,1,113,1,113,1,113, - 3,113,1195,8,113,1,114,1,114,1,114,1,114,1,115,1,115,1,115,1,115, - 5,115,1205,8,115,10,115,12,115,1208,9,115,1,115,1,115,1,115,1,115, - 3,115,1214,8,115,1,116,1,116,1,116,1,116,1,116,1,116,1,116,1,116, - 1,116,3,116,1225,8,116,1,117,1,117,1,117,0,0,118,0,2,4,6,8,10,12, - 14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56, - 58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100, - 102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132, - 134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164, - 166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196, - 198,200,202,204,206,208,210,212,214,216,218,220,222,224,226,228, - 230,232,234,0,10,1,0,130,131,1,0,7,8,1,0,16,23,1,0,81,82,1,0,158, - 159,1,0,126,127,3,0,30,37,39,48,50,70,3,0,29,29,38,38,49,49,1,0, - 135,150,6,0,10,13,15,115,117,117,119,129,132,135,137,157,1311,0, - 236,1,0,0,0,2,239,1,0,0,0,4,256,1,0,0,0,6,258,1,0,0,0,8,262,1,0, - 0,0,10,266,1,0,0,0,12,270,1,0,0,0,14,321,1,0,0,0,16,323,1,0,0,0, - 18,336,1,0,0,0,20,338,1,0,0,0,22,342,1,0,0,0,24,353,1,0,0,0,26,357, - 1,0,0,0,28,361,1,0,0,0,30,377,1,0,0,0,32,379,1,0,0,0,34,383,1,0, - 0,0,36,401,1,0,0,0,38,403,1,0,0,0,40,407,1,0,0,0,42,417,1,0,0,0, - 44,428,1,0,0,0,46,436,1,0,0,0,48,447,1,0,0,0,50,455,1,0,0,0,52,463, - 1,0,0,0,54,471,1,0,0,0,56,479,1,0,0,0,58,487,1,0,0,0,60,498,1,0, - 0,0,62,506,1,0,0,0,64,514,1,0,0,0,66,516,1,0,0,0,68,520,1,0,0,0, - 70,530,1,0,0,0,72,538,1,0,0,0,74,546,1,0,0,0,76,554,1,0,0,0,78,556, - 1,0,0,0,80,571,1,0,0,0,82,589,1,0,0,0,84,604,1,0,0,0,86,609,1,0, - 0,0,88,616,1,0,0,0,90,618,1,0,0,0,92,635,1,0,0,0,94,637,1,0,0,0, - 96,652,1,0,0,0,98,669,1,0,0,0,100,674,1,0,0,0,102,689,1,0,0,0,104, - 697,1,0,0,0,106,705,1,0,0,0,108,707,1,0,0,0,110,724,1,0,0,0,112, - 726,1,0,0,0,114,733,1,0,0,0,116,748,1,0,0,0,118,756,1,0,0,0,120, - 758,1,0,0,0,122,762,1,0,0,0,124,764,1,0,0,0,126,798,1,0,0,0,128, - 805,1,0,0,0,130,811,1,0,0,0,132,813,1,0,0,0,134,838,1,0,0,0,136, - 854,1,0,0,0,138,856,1,0,0,0,140,869,1,0,0,0,142,886,1,0,0,0,144, - 888,1,0,0,0,146,903,1,0,0,0,148,905,1,0,0,0,150,909,1,0,0,0,152, - 911,1,0,0,0,154,915,1,0,0,0,156,917,1,0,0,0,158,934,1,0,0,0,160, - 936,1,0,0,0,162,940,1,0,0,0,164,957,1,0,0,0,166,959,1,0,0,0,168, - 977,1,0,0,0,170,979,1,0,0,0,172,983,1,0,0,0,174,987,1,0,0,0,176, - 1006,1,0,0,0,178,1014,1,0,0,0,180,1022,1,0,0,0,182,1030,1,0,0,0, - 184,1038,1,0,0,0,186,1046,1,0,0,0,188,1048,1,0,0,0,190,1052,1,0, - 0,0,192,1067,1,0,0,0,194,1069,1,0,0,0,196,1084,1,0,0,0,198,1102, - 1,0,0,0,200,1104,1,0,0,0,202,1117,1,0,0,0,204,1121,1,0,0,0,206,1125, - 1,0,0,0,208,1129,1,0,0,0,210,1133,1,0,0,0,212,1137,1,0,0,0,214,1152, - 1,0,0,0,216,1169,1,0,0,0,218,1171,1,0,0,0,220,1173,1,0,0,0,222,1175, - 1,0,0,0,224,1179,1,0,0,0,226,1194,1,0,0,0,228,1196,1,0,0,0,230,1213, - 1,0,0,0,232,1224,1,0,0,0,234,1226,1,0,0,0,236,237,3,2,1,0,237,238, + 418,8,21,1,22,1,22,1,22,1,22,1,22,1,22,1,22,1,22,1,22,1,22,1,22, + 1,22,3,22,432,8,22,1,23,1,23,1,23,1,23,1,23,1,23,3,23,440,8,23,1, + 24,1,24,1,24,1,24,1,24,1,24,1,24,1,24,1,24,1,24,1,24,1,24,3,24,454, + 8,24,1,25,1,25,1,25,1,25,1,25,1,25,3,25,462,8,25,1,26,1,26,1,26, + 1,26,1,26,1,26,3,26,470,8,26,1,27,1,27,1,27,1,27,1,27,1,27,3,27, + 478,8,27,1,28,1,28,1,28,1,28,1,28,1,28,3,28,486,8,28,1,29,1,29,1, + 29,1,29,1,29,1,29,3,29,494,8,29,1,30,1,30,1,30,1,30,1,30,1,30,1, + 30,1,30,1,30,3,30,505,8,30,1,31,1,31,1,31,1,31,1,31,1,31,3,31,513, + 8,31,1,32,1,32,1,32,1,32,1,32,1,32,3,32,521,8,32,1,33,1,33,1,33, + 1,33,1,34,1,34,1,34,1,34,1,35,1,35,1,35,1,35,1,35,1,35,3,35,537, + 8,35,1,36,1,36,1,36,1,36,1,36,1,36,3,36,545,8,36,1,37,1,37,1,37, + 1,37,1,37,1,37,3,37,553,8,37,1,38,1,38,1,38,1,38,1,38,1,38,3,38, + 561,8,38,1,39,1,39,1,40,1,40,1,40,1,40,5,40,569,8,40,10,40,12,40, + 572,9,40,1,40,1,40,1,40,1,40,3,40,578,8,40,1,41,1,41,1,41,1,41,1, + 41,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,41,3,41,596, + 8,41,1,42,1,42,1,42,1,42,5,42,602,8,42,10,42,12,42,605,9,42,1,42, + 1,42,1,42,1,42,3,42,611,8,42,1,43,1,43,1,43,3,43,616,8,43,1,44,1, + 44,1,44,1,44,1,44,3,44,623,8,44,1,45,1,45,1,45,1,45,1,46,1,46,1, + 46,1,46,1,46,1,46,5,46,635,8,46,10,46,12,46,638,9,46,1,46,1,46,3, + 46,642,8,46,1,47,1,47,1,48,1,48,1,48,1,48,1,48,1,48,5,48,652,8,48, + 10,48,12,48,655,9,48,1,48,1,48,3,48,659,8,48,1,49,1,49,1,49,1,49, + 1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,49,3,49,676, + 8,49,1,50,1,50,1,50,3,50,681,8,50,1,51,1,51,1,51,1,51,1,51,1,51, + 5,51,689,8,51,10,51,12,51,692,9,51,1,51,1,51,3,51,696,8,51,1,52, + 1,52,1,52,1,52,1,52,1,52,3,52,704,8,52,1,53,1,53,1,53,1,53,1,53, + 1,53,3,53,712,8,53,1,54,1,54,1,54,1,54,1,55,1,55,1,55,1,55,1,55, + 1,55,5,55,724,8,55,10,55,12,55,727,9,55,1,55,1,55,3,55,731,8,55, + 1,56,1,56,1,56,1,56,1,57,1,57,1,57,3,57,740,8,57,1,58,1,58,1,58, + 1,58,1,58,1,58,5,58,748,8,58,10,58,12,58,751,9,58,1,58,1,58,3,58, + 755,8,58,1,59,1,59,1,59,1,59,1,59,1,59,3,59,763,8,59,1,60,1,60,1, + 60,1,60,1,61,1,61,1,62,1,62,1,62,1,62,1,62,1,62,5,62,777,8,62,10, + 62,12,62,780,9,62,1,62,1,62,1,63,1,63,1,63,1,63,4,63,788,8,63,11, + 63,12,63,789,1,63,1,63,1,63,1,63,1,63,1,63,5,63,798,8,63,10,63,12, + 63,801,9,63,1,63,1,63,3,63,805,8,63,1,64,1,64,1,64,1,64,1,64,3,64, + 812,8,64,1,65,1,65,1,65,1,65,3,65,818,8,65,1,66,1,66,1,66,1,66,1, + 66,1,66,1,66,5,66,827,8,66,10,66,12,66,830,9,66,1,66,1,66,3,66,834, + 8,66,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,3,67,845,8,67, + 1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,68, + 1,68,3,68,861,8,68,1,69,1,69,1,69,1,69,1,69,1,69,5,69,869,8,69,10, + 69,12,69,872,9,69,1,69,1,69,1,70,1,70,1,70,1,70,1,70,1,70,5,70,882, + 8,70,10,70,12,70,885,9,70,1,70,1,70,1,71,1,71,1,71,1,71,3,71,893, + 8,71,1,72,1,72,1,72,1,72,1,72,1,72,5,72,901,8,72,10,72,12,72,904, + 9,72,1,72,1,72,1,73,1,73,3,73,910,8,73,1,74,1,74,1,74,1,74,1,75, + 1,75,1,76,1,76,1,76,1,76,1,77,1,77,1,78,1,78,1,78,1,78,1,78,1,78, + 5,78,930,8,78,10,78,12,78,933,9,78,1,78,1,78,1,79,1,79,1,79,1,79, + 3,79,941,8,79,1,80,1,80,1,80,1,80,1,81,1,81,1,81,1,81,1,81,1,81, + 5,81,953,8,81,10,81,12,81,956,9,81,1,81,1,81,1,82,1,82,1,82,1,82, + 3,82,964,8,82,1,83,1,83,1,83,1,83,1,83,1,83,5,83,972,8,83,10,83, + 12,83,975,9,83,1,83,1,83,1,84,1,84,1,84,1,84,1,84,3,84,984,8,84, + 1,85,1,85,1,85,1,85,1,86,1,86,1,86,1,86,1,87,1,87,1,87,1,87,1,87, + 1,87,5,87,1000,8,87,10,87,12,87,1003,9,87,1,87,1,87,1,88,1,88,1, + 88,1,88,1,88,1,88,3,88,1013,8,88,1,89,1,89,1,89,1,89,1,89,1,89,3, + 89,1021,8,89,1,90,1,90,1,90,1,90,1,90,1,90,3,90,1029,8,90,1,91,1, + 91,1,91,1,91,1,91,1,91,3,91,1037,8,91,1,92,1,92,1,92,1,92,1,92,1, + 92,3,92,1045,8,92,1,93,1,93,1,93,1,93,1,93,1,93,3,93,1053,8,93,1, + 94,1,94,1,94,1,94,1,95,1,95,1,95,1,95,1,95,1,95,5,95,1065,8,95,10, + 95,12,95,1068,9,95,1,95,1,95,1,96,1,96,3,96,1074,8,96,1,97,1,97, + 1,97,1,97,1,97,1,97,5,97,1082,8,97,10,97,12,97,1085,9,97,3,97,1087, + 8,97,1,97,1,97,1,98,1,98,1,98,1,98,5,98,1095,8,98,10,98,12,98,1098, + 9,98,1,98,1,98,1,99,1,99,1,99,1,99,1,99,1,99,1,99,3,99,1109,8,99, + 1,100,1,100,1,100,1,100,1,100,1,100,5,100,1117,8,100,10,100,12,100, + 1120,9,100,1,100,1,100,1,101,1,101,1,101,1,101,1,102,1,102,1,102, + 1,102,1,103,1,103,1,103,1,103,1,104,1,104,1,104,1,104,1,105,1,105, + 1,105,1,105,1,106,1,106,1,106,1,106,1,106,1,106,5,106,1150,8,106, + 10,106,12,106,1153,9,106,3,106,1155,8,106,1,106,1,106,1,107,1,107, + 1,107,1,107,5,107,1163,8,107,10,107,12,107,1166,9,107,1,107,1,107, + 1,108,1,108,1,108,1,108,1,108,1,108,3,108,1176,8,108,1,109,1,109, + 1,110,1,110,1,111,1,111,1,112,1,112,3,112,1186,8,112,1,113,1,113, + 1,113,1,113,5,113,1192,8,113,10,113,12,113,1195,9,113,1,113,1,113, + 1,113,1,113,3,113,1201,8,113,1,114,1,114,1,114,1,114,1,115,1,115, + 1,115,1,115,5,115,1211,8,115,10,115,12,115,1214,9,115,1,115,1,115, + 1,115,1,115,3,115,1220,8,115,1,116,1,116,1,116,1,116,1,116,1,116, + 1,116,1,116,1,116,3,116,1231,8,116,1,117,1,117,1,117,0,0,118,0,2, + 4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48, + 50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92, + 94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126, + 128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158, + 160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190, + 192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222, + 224,226,228,230,232,234,0,10,1,0,130,131,1,0,7,8,1,0,16,23,1,0,81, + 82,1,0,158,159,1,0,126,127,3,0,30,37,39,48,50,70,3,0,29,29,38,38, + 49,49,1,0,135,150,6,0,10,13,15,115,117,117,119,129,132,135,137,157, + 1319,0,236,1,0,0,0,2,239,1,0,0,0,4,256,1,0,0,0,6,258,1,0,0,0,8,262, + 1,0,0,0,10,266,1,0,0,0,12,270,1,0,0,0,14,321,1,0,0,0,16,323,1,0, + 0,0,18,336,1,0,0,0,20,338,1,0,0,0,22,342,1,0,0,0,24,353,1,0,0,0, + 26,357,1,0,0,0,28,361,1,0,0,0,30,377,1,0,0,0,32,379,1,0,0,0,34,383, + 1,0,0,0,36,401,1,0,0,0,38,403,1,0,0,0,40,407,1,0,0,0,42,417,1,0, + 0,0,44,431,1,0,0,0,46,439,1,0,0,0,48,453,1,0,0,0,50,461,1,0,0,0, + 52,469,1,0,0,0,54,477,1,0,0,0,56,485,1,0,0,0,58,493,1,0,0,0,60,504, + 1,0,0,0,62,512,1,0,0,0,64,520,1,0,0,0,66,522,1,0,0,0,68,526,1,0, + 0,0,70,536,1,0,0,0,72,544,1,0,0,0,74,552,1,0,0,0,76,560,1,0,0,0, + 78,562,1,0,0,0,80,577,1,0,0,0,82,595,1,0,0,0,84,610,1,0,0,0,86,615, + 1,0,0,0,88,622,1,0,0,0,90,624,1,0,0,0,92,641,1,0,0,0,94,643,1,0, + 0,0,96,658,1,0,0,0,98,675,1,0,0,0,100,680,1,0,0,0,102,695,1,0,0, + 0,104,703,1,0,0,0,106,711,1,0,0,0,108,713,1,0,0,0,110,730,1,0,0, + 0,112,732,1,0,0,0,114,739,1,0,0,0,116,754,1,0,0,0,118,762,1,0,0, + 0,120,764,1,0,0,0,122,768,1,0,0,0,124,770,1,0,0,0,126,804,1,0,0, + 0,128,811,1,0,0,0,130,817,1,0,0,0,132,819,1,0,0,0,134,844,1,0,0, + 0,136,860,1,0,0,0,138,862,1,0,0,0,140,875,1,0,0,0,142,892,1,0,0, + 0,144,894,1,0,0,0,146,909,1,0,0,0,148,911,1,0,0,0,150,915,1,0,0, + 0,152,917,1,0,0,0,154,921,1,0,0,0,156,923,1,0,0,0,158,940,1,0,0, + 0,160,942,1,0,0,0,162,946,1,0,0,0,164,963,1,0,0,0,166,965,1,0,0, + 0,168,983,1,0,0,0,170,985,1,0,0,0,172,989,1,0,0,0,174,993,1,0,0, + 0,176,1012,1,0,0,0,178,1020,1,0,0,0,180,1028,1,0,0,0,182,1036,1, + 0,0,0,184,1044,1,0,0,0,186,1052,1,0,0,0,188,1054,1,0,0,0,190,1058, + 1,0,0,0,192,1073,1,0,0,0,194,1075,1,0,0,0,196,1090,1,0,0,0,198,1108, + 1,0,0,0,200,1110,1,0,0,0,202,1123,1,0,0,0,204,1127,1,0,0,0,206,1131, + 1,0,0,0,208,1135,1,0,0,0,210,1139,1,0,0,0,212,1143,1,0,0,0,214,1158, + 1,0,0,0,216,1175,1,0,0,0,218,1177,1,0,0,0,220,1179,1,0,0,0,222,1181, + 1,0,0,0,224,1185,1,0,0,0,226,1200,1,0,0,0,228,1202,1,0,0,0,230,1219, + 1,0,0,0,232,1230,1,0,0,0,234,1232,1,0,0,0,236,237,3,2,1,0,237,238, 5,0,0,1,238,1,1,0,0,0,239,240,5,5,0,0,240,245,3,4,2,0,241,242,5, 1,0,0,242,244,3,4,2,0,243,241,1,0,0,0,244,247,1,0,0,0,245,243,1, 0,0,0,245,246,1,0,0,0,246,248,1,0,0,0,247,245,1,0,0,0,248,249,5, @@ -216,264 +216,267 @@ def serializedATN(): 5,2,0,0,409,410,3,234,117,0,410,41,1,0,0,0,411,412,5,117,0,0,412, 413,5,2,0,0,413,418,5,156,0,0,414,415,5,117,0,0,415,416,5,2,0,0, 416,418,3,234,117,0,417,411,1,0,0,0,417,414,1,0,0,0,418,43,1,0,0, - 0,419,420,5,118,0,0,420,421,5,2,0,0,421,429,3,78,39,0,422,423,5, - 118,0,0,423,424,5,2,0,0,424,429,5,153,0,0,425,426,5,118,0,0,426, - 427,5,2,0,0,427,429,5,155,0,0,428,419,1,0,0,0,428,422,1,0,0,0,428, - 425,1,0,0,0,429,45,1,0,0,0,430,431,5,115,0,0,431,432,5,2,0,0,432, - 437,5,156,0,0,433,434,5,115,0,0,434,435,5,2,0,0,435,437,3,234,117, - 0,436,430,1,0,0,0,436,433,1,0,0,0,437,47,1,0,0,0,438,439,5,116,0, - 0,439,440,5,2,0,0,440,448,3,78,39,0,441,442,5,116,0,0,442,443,5, - 2,0,0,443,448,5,153,0,0,444,445,5,116,0,0,445,446,5,2,0,0,446,448, - 5,155,0,0,447,438,1,0,0,0,447,441,1,0,0,0,447,444,1,0,0,0,448,49, - 1,0,0,0,449,450,5,72,0,0,450,451,5,2,0,0,451,456,5,156,0,0,452,453, - 5,72,0,0,453,454,5,2,0,0,454,456,5,158,0,0,455,449,1,0,0,0,455,452, - 1,0,0,0,456,51,1,0,0,0,457,458,5,71,0,0,458,459,5,2,0,0,459,464, - 3,78,39,0,460,461,5,71,0,0,461,462,5,2,0,0,462,464,3,234,117,0,463, - 457,1,0,0,0,463,460,1,0,0,0,464,53,1,0,0,0,465,466,5,74,0,0,466, - 467,5,2,0,0,467,472,5,156,0,0,468,469,5,74,0,0,469,470,5,2,0,0,470, - 472,3,234,117,0,471,465,1,0,0,0,471,468,1,0,0,0,472,55,1,0,0,0,473, - 474,5,73,0,0,474,475,5,2,0,0,475,480,3,78,39,0,476,477,5,73,0,0, - 477,478,5,2,0,0,478,480,3,234,117,0,479,473,1,0,0,0,479,476,1,0, - 0,0,480,57,1,0,0,0,481,482,5,93,0,0,482,483,5,2,0,0,483,488,3,116, - 58,0,484,485,5,93,0,0,485,486,5,2,0,0,486,488,5,156,0,0,487,481, - 1,0,0,0,487,484,1,0,0,0,488,59,1,0,0,0,489,490,5,94,0,0,490,491, - 5,2,0,0,491,499,5,152,0,0,492,493,5,94,0,0,493,494,5,2,0,0,494,499, - 3,78,39,0,495,496,5,94,0,0,496,497,5,2,0,0,497,499,3,234,117,0,498, - 489,1,0,0,0,498,492,1,0,0,0,498,495,1,0,0,0,499,61,1,0,0,0,500,501, - 5,89,0,0,501,502,5,2,0,0,502,507,5,156,0,0,503,504,5,89,0,0,504, - 505,5,2,0,0,505,507,5,158,0,0,506,500,1,0,0,0,506,503,1,0,0,0,507, - 63,1,0,0,0,508,509,5,88,0,0,509,510,5,2,0,0,510,515,3,78,39,0,511, - 512,5,88,0,0,512,513,5,2,0,0,513,515,5,153,0,0,514,508,1,0,0,0,514, - 511,1,0,0,0,515,65,1,0,0,0,516,517,5,97,0,0,517,518,5,2,0,0,518, - 519,3,80,40,0,519,67,1,0,0,0,520,521,5,98,0,0,521,522,5,2,0,0,522, - 523,3,80,40,0,523,69,1,0,0,0,524,525,5,75,0,0,525,526,5,2,0,0,526, - 531,5,156,0,0,527,528,5,75,0,0,528,529,5,2,0,0,529,531,5,158,0,0, - 530,524,1,0,0,0,530,527,1,0,0,0,531,71,1,0,0,0,532,533,5,76,0,0, - 533,534,5,2,0,0,534,539,3,78,39,0,535,536,5,76,0,0,536,537,5,2,0, - 0,537,539,5,153,0,0,538,532,1,0,0,0,538,535,1,0,0,0,539,73,1,0,0, - 0,540,541,5,77,0,0,541,542,5,2,0,0,542,547,5,156,0,0,543,544,5,77, - 0,0,544,545,5,2,0,0,545,547,5,158,0,0,546,540,1,0,0,0,546,543,1, - 0,0,0,547,75,1,0,0,0,548,549,5,78,0,0,549,550,5,2,0,0,550,555,3, - 78,39,0,551,552,5,78,0,0,552,553,5,2,0,0,553,555,5,153,0,0,554,548, - 1,0,0,0,554,551,1,0,0,0,555,77,1,0,0,0,556,557,5,154,0,0,557,79, - 1,0,0,0,558,559,5,5,0,0,559,564,3,82,41,0,560,561,5,1,0,0,561,563, - 3,82,41,0,562,560,1,0,0,0,563,566,1,0,0,0,564,562,1,0,0,0,564,565, - 1,0,0,0,565,567,1,0,0,0,566,564,1,0,0,0,567,568,5,6,0,0,568,572, - 1,0,0,0,569,570,5,5,0,0,570,572,5,6,0,0,571,558,1,0,0,0,571,569, - 1,0,0,0,572,81,1,0,0,0,573,574,5,151,0,0,574,575,5,2,0,0,575,590, - 5,153,0,0,576,577,5,151,0,0,577,578,5,2,0,0,578,590,5,152,0,0,579, - 580,5,151,0,0,580,581,5,2,0,0,581,590,5,155,0,0,582,583,5,151,0, - 0,583,584,5,2,0,0,584,590,3,78,39,0,585,586,3,234,117,0,586,587, - 5,2,0,0,587,588,3,86,43,0,588,590,1,0,0,0,589,573,1,0,0,0,589,576, - 1,0,0,0,589,579,1,0,0,0,589,582,1,0,0,0,589,585,1,0,0,0,590,83,1, - 0,0,0,591,592,5,3,0,0,592,597,3,86,43,0,593,594,5,1,0,0,594,596, - 3,86,43,0,595,593,1,0,0,0,596,599,1,0,0,0,597,595,1,0,0,0,597,598, - 1,0,0,0,598,600,1,0,0,0,599,597,1,0,0,0,600,601,5,4,0,0,601,605, - 1,0,0,0,602,603,5,3,0,0,603,605,5,4,0,0,604,591,1,0,0,0,604,602, - 1,0,0,0,605,85,1,0,0,0,606,610,3,84,42,0,607,610,3,80,40,0,608,610, - 3,88,44,0,609,606,1,0,0,0,609,607,1,0,0,0,609,608,1,0,0,0,610,87, - 1,0,0,0,611,617,5,159,0,0,612,617,5,158,0,0,613,617,7,1,0,0,614, - 617,5,9,0,0,615,617,3,234,117,0,616,611,1,0,0,0,616,612,1,0,0,0, - 616,613,1,0,0,0,616,614,1,0,0,0,616,615,1,0,0,0,617,89,1,0,0,0,618, - 619,5,132,0,0,619,620,5,2,0,0,620,621,3,92,46,0,621,91,1,0,0,0,622, - 623,5,5,0,0,623,636,5,6,0,0,624,625,5,5,0,0,625,630,3,94,47,0,626, - 627,5,1,0,0,627,629,3,94,47,0,628,626,1,0,0,0,629,632,1,0,0,0,630, - 628,1,0,0,0,630,631,1,0,0,0,631,633,1,0,0,0,632,630,1,0,0,0,633, - 634,5,6,0,0,634,636,1,0,0,0,635,622,1,0,0,0,635,624,1,0,0,0,636, - 93,1,0,0,0,637,638,3,98,49,0,638,95,1,0,0,0,639,640,5,5,0,0,640, - 653,5,6,0,0,641,642,5,5,0,0,642,647,3,98,49,0,643,644,5,1,0,0,644, - 646,3,98,49,0,645,643,1,0,0,0,646,649,1,0,0,0,647,645,1,0,0,0,647, - 648,1,0,0,0,648,650,1,0,0,0,649,647,1,0,0,0,650,651,5,6,0,0,651, - 653,1,0,0,0,652,639,1,0,0,0,652,641,1,0,0,0,653,97,1,0,0,0,654,655, - 5,151,0,0,655,656,5,2,0,0,656,670,5,153,0,0,657,658,5,151,0,0,658, - 659,5,2,0,0,659,670,5,152,0,0,660,661,5,151,0,0,661,662,5,2,0,0, - 662,670,3,78,39,0,663,664,5,151,0,0,664,665,5,2,0,0,665,670,5,155, - 0,0,666,667,5,157,0,0,667,668,5,2,0,0,668,670,3,100,50,0,669,654, - 1,0,0,0,669,657,1,0,0,0,669,660,1,0,0,0,669,663,1,0,0,0,669,666, - 1,0,0,0,670,99,1,0,0,0,671,675,3,96,48,0,672,675,3,102,51,0,673, - 675,3,104,52,0,674,671,1,0,0,0,674,672,1,0,0,0,674,673,1,0,0,0,675, - 101,1,0,0,0,676,677,5,3,0,0,677,690,5,4,0,0,678,679,5,3,0,0,679, - 684,3,100,50,0,680,681,5,1,0,0,681,683,3,100,50,0,682,680,1,0,0, - 0,683,686,1,0,0,0,684,682,1,0,0,0,684,685,1,0,0,0,685,687,1,0,0, - 0,686,684,1,0,0,0,687,688,5,4,0,0,688,690,1,0,0,0,689,676,1,0,0, - 0,689,678,1,0,0,0,690,103,1,0,0,0,691,698,5,159,0,0,692,698,5,158, - 0,0,693,698,7,1,0,0,694,698,5,9,0,0,695,698,5,156,0,0,696,698,3, - 234,117,0,697,691,1,0,0,0,697,692,1,0,0,0,697,693,1,0,0,0,697,694, - 1,0,0,0,697,695,1,0,0,0,697,696,1,0,0,0,698,105,1,0,0,0,699,700, - 5,134,0,0,700,701,5,2,0,0,701,706,3,110,55,0,702,703,5,134,0,0,703, - 704,5,2,0,0,704,706,5,156,0,0,705,699,1,0,0,0,705,702,1,0,0,0,706, - 107,1,0,0,0,707,708,5,133,0,0,708,709,5,2,0,0,709,710,3,114,57,0, - 710,109,1,0,0,0,711,712,5,5,0,0,712,725,5,6,0,0,713,714,5,5,0,0, - 714,719,3,112,56,0,715,716,5,1,0,0,716,718,3,112,56,0,717,715,1, - 0,0,0,718,721,1,0,0,0,719,717,1,0,0,0,719,720,1,0,0,0,720,722,1, - 0,0,0,721,719,1,0,0,0,722,723,5,6,0,0,723,725,1,0,0,0,724,711,1, - 0,0,0,724,713,1,0,0,0,725,111,1,0,0,0,726,727,3,234,117,0,727,728, - 5,2,0,0,728,729,3,114,57,0,729,113,1,0,0,0,730,734,3,110,55,0,731, - 734,3,116,58,0,732,734,3,118,59,0,733,730,1,0,0,0,733,731,1,0,0, - 0,733,732,1,0,0,0,734,115,1,0,0,0,735,736,5,3,0,0,736,749,5,4,0, - 0,737,738,5,3,0,0,738,743,3,114,57,0,739,740,5,1,0,0,740,742,3,114, - 57,0,741,739,1,0,0,0,742,745,1,0,0,0,743,741,1,0,0,0,743,744,1,0, - 0,0,744,746,1,0,0,0,745,743,1,0,0,0,746,747,5,4,0,0,747,749,1,0, - 0,0,748,735,1,0,0,0,748,737,1,0,0,0,749,117,1,0,0,0,750,757,5,159, - 0,0,751,757,5,158,0,0,752,757,7,1,0,0,753,757,5,9,0,0,754,757,5, - 156,0,0,755,757,3,234,117,0,756,750,1,0,0,0,756,751,1,0,0,0,756, - 752,1,0,0,0,756,753,1,0,0,0,756,754,1,0,0,0,756,755,1,0,0,0,757, - 119,1,0,0,0,758,759,5,99,0,0,759,760,5,2,0,0,760,761,3,80,40,0,761, - 121,1,0,0,0,762,763,7,2,0,0,763,123,1,0,0,0,764,765,5,24,0,0,765, - 766,5,2,0,0,766,767,5,3,0,0,767,772,3,126,63,0,768,769,5,1,0,0,769, - 771,3,126,63,0,770,768,1,0,0,0,771,774,1,0,0,0,772,770,1,0,0,0,772, - 773,1,0,0,0,773,775,1,0,0,0,774,772,1,0,0,0,775,776,5,4,0,0,776, - 125,1,0,0,0,777,778,5,5,0,0,778,781,3,128,64,0,779,780,5,1,0,0,780, - 782,3,128,64,0,781,779,1,0,0,0,782,783,1,0,0,0,783,781,1,0,0,0,783, - 784,1,0,0,0,784,785,1,0,0,0,785,786,5,6,0,0,786,799,1,0,0,0,787, - 788,5,5,0,0,788,793,3,130,65,0,789,790,5,1,0,0,790,792,3,130,65, - 0,791,789,1,0,0,0,792,795,1,0,0,0,793,791,1,0,0,0,793,794,1,0,0, - 0,794,796,1,0,0,0,795,793,1,0,0,0,796,797,5,6,0,0,797,799,1,0,0, - 0,798,777,1,0,0,0,798,787,1,0,0,0,799,127,1,0,0,0,800,806,3,134, - 67,0,801,806,3,136,68,0,802,806,3,26,13,0,803,806,3,90,45,0,804, - 806,3,8,4,0,805,800,1,0,0,0,805,801,1,0,0,0,805,802,1,0,0,0,805, - 803,1,0,0,0,805,804,1,0,0,0,806,129,1,0,0,0,807,812,3,132,66,0,808, - 812,3,26,13,0,809,812,3,90,45,0,810,812,3,8,4,0,811,807,1,0,0,0, - 811,808,1,0,0,0,811,809,1,0,0,0,811,810,1,0,0,0,812,131,1,0,0,0, - 813,814,3,220,110,0,814,827,5,2,0,0,815,828,3,126,63,0,816,817,5, - 3,0,0,817,822,3,126,63,0,818,819,5,1,0,0,819,821,3,126,63,0,820, - 818,1,0,0,0,821,824,1,0,0,0,822,820,1,0,0,0,822,823,1,0,0,0,823, - 825,1,0,0,0,824,822,1,0,0,0,825,826,5,4,0,0,826,828,1,0,0,0,827, - 815,1,0,0,0,827,816,1,0,0,0,828,133,1,0,0,0,829,830,5,26,0,0,830, - 831,5,2,0,0,831,839,5,153,0,0,832,833,5,26,0,0,833,834,5,2,0,0,834, - 839,3,78,39,0,835,836,5,26,0,0,836,837,5,2,0,0,837,839,5,152,0,0, - 838,829,1,0,0,0,838,832,1,0,0,0,838,835,1,0,0,0,839,135,1,0,0,0, - 840,841,5,25,0,0,841,842,5,2,0,0,842,855,7,1,0,0,843,844,5,25,0, - 0,844,845,5,2,0,0,845,855,5,156,0,0,846,847,3,218,109,0,847,848, - 5,2,0,0,848,849,3,78,39,0,849,855,1,0,0,0,850,851,3,218,109,0,851, - 852,5,2,0,0,852,853,3,232,116,0,853,855,1,0,0,0,854,840,1,0,0,0, - 854,843,1,0,0,0,854,846,1,0,0,0,854,850,1,0,0,0,855,137,1,0,0,0, - 856,857,5,28,0,0,857,858,5,2,0,0,858,859,5,3,0,0,859,864,3,2,1,0, - 860,861,5,1,0,0,861,863,3,2,1,0,862,860,1,0,0,0,863,866,1,0,0,0, - 864,862,1,0,0,0,864,865,1,0,0,0,865,867,1,0,0,0,866,864,1,0,0,0, - 867,868,5,4,0,0,868,139,1,0,0,0,869,870,5,85,0,0,870,871,5,2,0,0, - 871,872,5,5,0,0,872,877,3,142,71,0,873,874,5,1,0,0,874,876,3,142, - 71,0,875,873,1,0,0,0,876,879,1,0,0,0,877,875,1,0,0,0,877,878,1,0, - 0,0,878,880,1,0,0,0,879,877,1,0,0,0,880,881,5,6,0,0,881,141,1,0, - 0,0,882,887,3,144,72,0,883,887,3,6,3,0,884,887,3,16,8,0,885,887, - 3,8,4,0,886,882,1,0,0,0,886,883,1,0,0,0,886,884,1,0,0,0,886,885, - 1,0,0,0,887,143,1,0,0,0,888,889,5,79,0,0,889,890,5,2,0,0,890,891, - 5,5,0,0,891,896,3,146,73,0,892,893,5,1,0,0,893,895,3,146,73,0,894, - 892,1,0,0,0,895,898,1,0,0,0,896,894,1,0,0,0,896,897,1,0,0,0,897, - 899,1,0,0,0,898,896,1,0,0,0,899,900,5,6,0,0,900,145,1,0,0,0,901, - 904,3,148,74,0,902,904,3,152,76,0,903,901,1,0,0,0,903,902,1,0,0, - 0,904,147,1,0,0,0,905,906,5,80,0,0,906,907,5,2,0,0,907,908,3,150, - 75,0,908,149,1,0,0,0,909,910,7,3,0,0,910,151,1,0,0,0,911,912,5,83, - 0,0,912,913,5,2,0,0,913,914,3,154,77,0,914,153,1,0,0,0,915,916,5, - 84,0,0,916,155,1,0,0,0,917,918,5,86,0,0,918,919,5,2,0,0,919,920, - 5,5,0,0,920,925,3,158,79,0,921,922,5,1,0,0,922,924,3,158,79,0,923, - 921,1,0,0,0,924,927,1,0,0,0,925,923,1,0,0,0,925,926,1,0,0,0,926, - 928,1,0,0,0,927,925,1,0,0,0,928,929,5,6,0,0,929,157,1,0,0,0,930, - 935,3,6,3,0,931,935,3,16,8,0,932,935,3,8,4,0,933,935,3,144,72,0, - 934,930,1,0,0,0,934,931,1,0,0,0,934,932,1,0,0,0,934,933,1,0,0,0, - 935,159,1,0,0,0,936,937,5,87,0,0,937,938,5,2,0,0,938,939,3,80,40, - 0,939,161,1,0,0,0,940,941,5,100,0,0,941,942,5,2,0,0,942,943,5,5, - 0,0,943,948,3,164,82,0,944,945,5,1,0,0,945,947,3,164,82,0,946,944, - 1,0,0,0,947,950,1,0,0,0,948,946,1,0,0,0,948,949,1,0,0,0,949,951, - 1,0,0,0,950,948,1,0,0,0,951,952,5,6,0,0,952,163,1,0,0,0,953,958, - 3,28,14,0,954,958,3,166,83,0,955,958,3,66,33,0,956,958,3,106,53, - 0,957,953,1,0,0,0,957,954,1,0,0,0,957,955,1,0,0,0,957,956,1,0,0, - 0,958,165,1,0,0,0,959,960,5,101,0,0,960,961,5,2,0,0,961,962,5,5, - 0,0,962,967,3,168,84,0,963,964,5,1,0,0,964,966,3,168,84,0,965,963, - 1,0,0,0,966,969,1,0,0,0,967,965,1,0,0,0,967,968,1,0,0,0,968,970, - 1,0,0,0,969,967,1,0,0,0,970,971,5,6,0,0,971,167,1,0,0,0,972,978, - 3,170,85,0,973,978,3,172,86,0,974,978,3,174,87,0,975,978,3,176,88, - 0,976,978,3,178,89,0,977,972,1,0,0,0,977,973,1,0,0,0,977,974,1,0, - 0,0,977,975,1,0,0,0,977,976,1,0,0,0,978,169,1,0,0,0,979,980,5,102, - 0,0,980,981,5,2,0,0,981,982,3,234,117,0,982,171,1,0,0,0,983,984, - 5,103,0,0,984,985,5,2,0,0,985,986,3,234,117,0,986,173,1,0,0,0,987, - 988,5,104,0,0,988,989,5,2,0,0,989,990,5,3,0,0,990,995,3,234,117, - 0,991,992,5,1,0,0,992,994,3,234,117,0,993,991,1,0,0,0,994,997,1, - 0,0,0,995,993,1,0,0,0,995,996,1,0,0,0,996,998,1,0,0,0,997,995,1, - 0,0,0,998,999,5,4,0,0,999,175,1,0,0,0,1000,1001,5,105,0,0,1001,1002, - 5,2,0,0,1002,1007,5,156,0,0,1003,1004,5,105,0,0,1004,1005,5,2,0, - 0,1005,1007,5,158,0,0,1006,1000,1,0,0,0,1006,1003,1,0,0,0,1007,177, - 1,0,0,0,1008,1009,5,106,0,0,1009,1010,5,2,0,0,1010,1015,3,78,39, - 0,1011,1012,5,106,0,0,1012,1013,5,2,0,0,1013,1015,5,153,0,0,1014, - 1008,1,0,0,0,1014,1011,1,0,0,0,1015,179,1,0,0,0,1016,1017,5,107, - 0,0,1017,1018,5,2,0,0,1018,1023,5,156,0,0,1019,1020,5,107,0,0,1020, - 1021,5,2,0,0,1021,1023,5,158,0,0,1022,1016,1,0,0,0,1022,1019,1,0, - 0,0,1023,181,1,0,0,0,1024,1025,5,108,0,0,1025,1026,5,2,0,0,1026, - 1031,3,78,39,0,1027,1028,5,108,0,0,1028,1029,5,2,0,0,1029,1031,5, - 153,0,0,1030,1024,1,0,0,0,1030,1027,1,0,0,0,1031,183,1,0,0,0,1032, - 1033,5,109,0,0,1033,1034,5,2,0,0,1034,1039,5,156,0,0,1035,1036,5, - 109,0,0,1036,1037,5,2,0,0,1037,1039,5,159,0,0,1038,1032,1,0,0,0, - 1038,1035,1,0,0,0,1039,185,1,0,0,0,1040,1041,5,110,0,0,1041,1042, - 5,2,0,0,1042,1047,3,78,39,0,1043,1044,5,110,0,0,1044,1045,5,2,0, - 0,1045,1047,5,153,0,0,1046,1040,1,0,0,0,1046,1043,1,0,0,0,1047,187, - 1,0,0,0,1048,1049,5,111,0,0,1049,1050,5,2,0,0,1050,1051,3,234,117, - 0,1051,189,1,0,0,0,1052,1053,5,112,0,0,1053,1054,5,2,0,0,1054,1055, - 5,5,0,0,1055,1060,3,192,96,0,1056,1057,5,1,0,0,1057,1059,3,192,96, - 0,1058,1056,1,0,0,0,1059,1062,1,0,0,0,1060,1058,1,0,0,0,1060,1061, - 1,0,0,0,1061,1063,1,0,0,0,1062,1060,1,0,0,0,1063,1064,5,6,0,0,1064, - 191,1,0,0,0,1065,1068,3,28,14,0,1066,1068,3,66,33,0,1067,1065,1, - 0,0,0,1067,1066,1,0,0,0,1068,193,1,0,0,0,1069,1070,5,119,0,0,1070, - 1071,5,2,0,0,1071,1080,5,3,0,0,1072,1077,3,196,98,0,1073,1074,5, - 1,0,0,1074,1076,3,196,98,0,1075,1073,1,0,0,0,1076,1079,1,0,0,0,1077, - 1075,1,0,0,0,1077,1078,1,0,0,0,1078,1081,1,0,0,0,1079,1077,1,0,0, - 0,1080,1072,1,0,0,0,1080,1081,1,0,0,0,1081,1082,1,0,0,0,1082,1083, - 5,4,0,0,1083,195,1,0,0,0,1084,1085,5,5,0,0,1085,1090,3,198,99,0, - 1086,1087,5,1,0,0,1087,1089,3,198,99,0,1088,1086,1,0,0,0,1089,1092, - 1,0,0,0,1090,1088,1,0,0,0,1090,1091,1,0,0,0,1091,1093,1,0,0,0,1092, - 1090,1,0,0,0,1093,1094,5,6,0,0,1094,197,1,0,0,0,1095,1103,3,200, - 100,0,1096,1103,3,202,101,0,1097,1103,3,204,102,0,1098,1103,3,206, - 103,0,1099,1103,3,208,104,0,1100,1103,3,210,105,0,1101,1103,3,8, - 4,0,1102,1095,1,0,0,0,1102,1096,1,0,0,0,1102,1097,1,0,0,0,1102,1098, - 1,0,0,0,1102,1099,1,0,0,0,1102,1100,1,0,0,0,1102,1101,1,0,0,0,1103, - 199,1,0,0,0,1104,1105,5,120,0,0,1105,1106,5,2,0,0,1106,1107,5,3, - 0,0,1107,1112,3,224,112,0,1108,1109,5,1,0,0,1109,1111,3,224,112, - 0,1110,1108,1,0,0,0,1111,1114,1,0,0,0,1112,1110,1,0,0,0,1112,1113, - 1,0,0,0,1113,1115,1,0,0,0,1114,1112,1,0,0,0,1115,1116,5,4,0,0,1116, - 201,1,0,0,0,1117,1118,5,121,0,0,1118,1119,5,2,0,0,1119,1120,5,158, - 0,0,1120,203,1,0,0,0,1121,1122,5,122,0,0,1122,1123,5,2,0,0,1123, - 1124,5,158,0,0,1124,205,1,0,0,0,1125,1126,5,123,0,0,1126,1127,5, - 2,0,0,1127,1128,7,4,0,0,1128,207,1,0,0,0,1129,1130,5,124,0,0,1130, - 1131,5,2,0,0,1131,1132,5,158,0,0,1132,209,1,0,0,0,1133,1134,5,125, - 0,0,1134,1135,5,2,0,0,1135,1136,7,5,0,0,1136,211,1,0,0,0,1137,1138, - 5,128,0,0,1138,1139,5,2,0,0,1139,1148,5,3,0,0,1140,1145,3,214,107, - 0,1141,1142,5,1,0,0,1142,1144,3,214,107,0,1143,1141,1,0,0,0,1144, - 1147,1,0,0,0,1145,1143,1,0,0,0,1145,1146,1,0,0,0,1146,1149,1,0,0, - 0,1147,1145,1,0,0,0,1148,1140,1,0,0,0,1148,1149,1,0,0,0,1149,1150, - 1,0,0,0,1150,1151,5,4,0,0,1151,213,1,0,0,0,1152,1153,5,5,0,0,1153, - 1158,3,216,108,0,1154,1155,5,1,0,0,1155,1157,3,216,108,0,1156,1154, - 1,0,0,0,1157,1160,1,0,0,0,1158,1156,1,0,0,0,1158,1159,1,0,0,0,1159, - 1161,1,0,0,0,1160,1158,1,0,0,0,1161,1162,5,6,0,0,1162,215,1,0,0, - 0,1163,1170,3,200,100,0,1164,1170,3,34,17,0,1165,1170,3,26,13,0, - 1166,1170,3,90,45,0,1167,1170,3,108,54,0,1168,1170,3,8,4,0,1169, - 1163,1,0,0,0,1169,1164,1,0,0,0,1169,1165,1,0,0,0,1169,1166,1,0,0, - 0,1169,1167,1,0,0,0,1169,1168,1,0,0,0,1170,217,1,0,0,0,1171,1172, - 7,6,0,0,1172,219,1,0,0,0,1173,1174,7,7,0,0,1174,221,1,0,0,0,1175, - 1176,7,8,0,0,1176,223,1,0,0,0,1177,1180,3,222,111,0,1178,1180,3, - 234,117,0,1179,1177,1,0,0,0,1179,1178,1,0,0,0,1180,225,1,0,0,0,1181, - 1182,5,5,0,0,1182,1187,3,228,114,0,1183,1184,5,1,0,0,1184,1186,3, - 228,114,0,1185,1183,1,0,0,0,1186,1189,1,0,0,0,1187,1185,1,0,0,0, - 1187,1188,1,0,0,0,1188,1190,1,0,0,0,1189,1187,1,0,0,0,1190,1191, - 5,6,0,0,1191,1195,1,0,0,0,1192,1193,5,5,0,0,1193,1195,5,6,0,0,1194, - 1181,1,0,0,0,1194,1192,1,0,0,0,1195,227,1,0,0,0,1196,1197,3,234, - 117,0,1197,1198,5,2,0,0,1198,1199,3,232,116,0,1199,229,1,0,0,0,1200, - 1201,5,3,0,0,1201,1206,3,232,116,0,1202,1203,5,1,0,0,1203,1205,3, - 232,116,0,1204,1202,1,0,0,0,1205,1208,1,0,0,0,1206,1204,1,0,0,0, - 1206,1207,1,0,0,0,1207,1209,1,0,0,0,1208,1206,1,0,0,0,1209,1210, - 5,4,0,0,1210,1214,1,0,0,0,1211,1212,5,3,0,0,1212,1214,5,4,0,0,1213, - 1200,1,0,0,0,1213,1211,1,0,0,0,1214,231,1,0,0,0,1215,1225,5,159, - 0,0,1216,1225,5,158,0,0,1217,1225,5,7,0,0,1218,1225,5,8,0,0,1219, - 1225,5,9,0,0,1220,1225,3,228,114,0,1221,1225,3,230,115,0,1222,1225, - 3,226,113,0,1223,1225,3,234,117,0,1224,1215,1,0,0,0,1224,1216,1, - 0,0,0,1224,1217,1,0,0,0,1224,1218,1,0,0,0,1224,1219,1,0,0,0,1224, - 1220,1,0,0,0,1224,1221,1,0,0,0,1224,1222,1,0,0,0,1224,1223,1,0,0, - 0,1225,233,1,0,0,0,1226,1227,7,9,0,0,1227,235,1,0,0,0,94,245,256, - 321,331,348,375,377,387,399,401,417,428,436,447,455,463,471,479, - 487,498,506,514,530,538,546,554,564,571,589,597,604,609,616,630, - 635,647,652,669,674,684,689,697,705,719,724,733,743,748,756,772, - 783,793,798,805,811,822,827,838,854,864,877,886,896,903,925,934, - 948,957,967,977,995,1006,1014,1022,1030,1038,1046,1060,1067,1077, - 1080,1090,1102,1112,1145,1148,1158,1169,1179,1187,1194,1206,1213, - 1224 + 0,419,420,5,118,0,0,420,421,5,2,0,0,421,432,3,78,39,0,422,423,5, + 118,0,0,423,424,5,2,0,0,424,432,5,153,0,0,425,426,5,118,0,0,426, + 427,5,2,0,0,427,432,5,152,0,0,428,429,5,118,0,0,429,430,5,2,0,0, + 430,432,5,155,0,0,431,419,1,0,0,0,431,422,1,0,0,0,431,425,1,0,0, + 0,431,428,1,0,0,0,432,45,1,0,0,0,433,434,5,115,0,0,434,435,5,2,0, + 0,435,440,5,156,0,0,436,437,5,115,0,0,437,438,5,2,0,0,438,440,3, + 234,117,0,439,433,1,0,0,0,439,436,1,0,0,0,440,47,1,0,0,0,441,442, + 5,116,0,0,442,443,5,2,0,0,443,454,3,78,39,0,444,445,5,116,0,0,445, + 446,5,2,0,0,446,454,5,153,0,0,447,448,5,116,0,0,448,449,5,2,0,0, + 449,454,5,152,0,0,450,451,5,116,0,0,451,452,5,2,0,0,452,454,5,155, + 0,0,453,441,1,0,0,0,453,444,1,0,0,0,453,447,1,0,0,0,453,450,1,0, + 0,0,454,49,1,0,0,0,455,456,5,72,0,0,456,457,5,2,0,0,457,462,5,156, + 0,0,458,459,5,72,0,0,459,460,5,2,0,0,460,462,5,158,0,0,461,455,1, + 0,0,0,461,458,1,0,0,0,462,51,1,0,0,0,463,464,5,71,0,0,464,465,5, + 2,0,0,465,470,3,78,39,0,466,467,5,71,0,0,467,468,5,2,0,0,468,470, + 3,234,117,0,469,463,1,0,0,0,469,466,1,0,0,0,470,53,1,0,0,0,471,472, + 5,74,0,0,472,473,5,2,0,0,473,478,5,156,0,0,474,475,5,74,0,0,475, + 476,5,2,0,0,476,478,3,234,117,0,477,471,1,0,0,0,477,474,1,0,0,0, + 478,55,1,0,0,0,479,480,5,73,0,0,480,481,5,2,0,0,481,486,3,78,39, + 0,482,483,5,73,0,0,483,484,5,2,0,0,484,486,3,234,117,0,485,479,1, + 0,0,0,485,482,1,0,0,0,486,57,1,0,0,0,487,488,5,93,0,0,488,489,5, + 2,0,0,489,494,3,116,58,0,490,491,5,93,0,0,491,492,5,2,0,0,492,494, + 5,156,0,0,493,487,1,0,0,0,493,490,1,0,0,0,494,59,1,0,0,0,495,496, + 5,94,0,0,496,497,5,2,0,0,497,505,5,152,0,0,498,499,5,94,0,0,499, + 500,5,2,0,0,500,505,3,78,39,0,501,502,5,94,0,0,502,503,5,2,0,0,503, + 505,3,234,117,0,504,495,1,0,0,0,504,498,1,0,0,0,504,501,1,0,0,0, + 505,61,1,0,0,0,506,507,5,89,0,0,507,508,5,2,0,0,508,513,5,156,0, + 0,509,510,5,89,0,0,510,511,5,2,0,0,511,513,5,158,0,0,512,506,1,0, + 0,0,512,509,1,0,0,0,513,63,1,0,0,0,514,515,5,88,0,0,515,516,5,2, + 0,0,516,521,3,78,39,0,517,518,5,88,0,0,518,519,5,2,0,0,519,521,5, + 153,0,0,520,514,1,0,0,0,520,517,1,0,0,0,521,65,1,0,0,0,522,523,5, + 97,0,0,523,524,5,2,0,0,524,525,3,80,40,0,525,67,1,0,0,0,526,527, + 5,98,0,0,527,528,5,2,0,0,528,529,3,80,40,0,529,69,1,0,0,0,530,531, + 5,75,0,0,531,532,5,2,0,0,532,537,5,156,0,0,533,534,5,75,0,0,534, + 535,5,2,0,0,535,537,5,158,0,0,536,530,1,0,0,0,536,533,1,0,0,0,537, + 71,1,0,0,0,538,539,5,76,0,0,539,540,5,2,0,0,540,545,3,78,39,0,541, + 542,5,76,0,0,542,543,5,2,0,0,543,545,5,153,0,0,544,538,1,0,0,0,544, + 541,1,0,0,0,545,73,1,0,0,0,546,547,5,77,0,0,547,548,5,2,0,0,548, + 553,5,156,0,0,549,550,5,77,0,0,550,551,5,2,0,0,551,553,5,158,0,0, + 552,546,1,0,0,0,552,549,1,0,0,0,553,75,1,0,0,0,554,555,5,78,0,0, + 555,556,5,2,0,0,556,561,3,78,39,0,557,558,5,78,0,0,558,559,5,2,0, + 0,559,561,5,153,0,0,560,554,1,0,0,0,560,557,1,0,0,0,561,77,1,0,0, + 0,562,563,5,154,0,0,563,79,1,0,0,0,564,565,5,5,0,0,565,570,3,82, + 41,0,566,567,5,1,0,0,567,569,3,82,41,0,568,566,1,0,0,0,569,572,1, + 0,0,0,570,568,1,0,0,0,570,571,1,0,0,0,571,573,1,0,0,0,572,570,1, + 0,0,0,573,574,5,6,0,0,574,578,1,0,0,0,575,576,5,5,0,0,576,578,5, + 6,0,0,577,564,1,0,0,0,577,575,1,0,0,0,578,81,1,0,0,0,579,580,5,151, + 0,0,580,581,5,2,0,0,581,596,5,153,0,0,582,583,5,151,0,0,583,584, + 5,2,0,0,584,596,5,152,0,0,585,586,5,151,0,0,586,587,5,2,0,0,587, + 596,5,155,0,0,588,589,5,151,0,0,589,590,5,2,0,0,590,596,3,78,39, + 0,591,592,3,234,117,0,592,593,5,2,0,0,593,594,3,86,43,0,594,596, + 1,0,0,0,595,579,1,0,0,0,595,582,1,0,0,0,595,585,1,0,0,0,595,588, + 1,0,0,0,595,591,1,0,0,0,596,83,1,0,0,0,597,598,5,3,0,0,598,603,3, + 86,43,0,599,600,5,1,0,0,600,602,3,86,43,0,601,599,1,0,0,0,602,605, + 1,0,0,0,603,601,1,0,0,0,603,604,1,0,0,0,604,606,1,0,0,0,605,603, + 1,0,0,0,606,607,5,4,0,0,607,611,1,0,0,0,608,609,5,3,0,0,609,611, + 5,4,0,0,610,597,1,0,0,0,610,608,1,0,0,0,611,85,1,0,0,0,612,616,3, + 84,42,0,613,616,3,80,40,0,614,616,3,88,44,0,615,612,1,0,0,0,615, + 613,1,0,0,0,615,614,1,0,0,0,616,87,1,0,0,0,617,623,5,159,0,0,618, + 623,5,158,0,0,619,623,7,1,0,0,620,623,5,9,0,0,621,623,3,234,117, + 0,622,617,1,0,0,0,622,618,1,0,0,0,622,619,1,0,0,0,622,620,1,0,0, + 0,622,621,1,0,0,0,623,89,1,0,0,0,624,625,5,132,0,0,625,626,5,2,0, + 0,626,627,3,92,46,0,627,91,1,0,0,0,628,629,5,5,0,0,629,642,5,6,0, + 0,630,631,5,5,0,0,631,636,3,94,47,0,632,633,5,1,0,0,633,635,3,94, + 47,0,634,632,1,0,0,0,635,638,1,0,0,0,636,634,1,0,0,0,636,637,1,0, + 0,0,637,639,1,0,0,0,638,636,1,0,0,0,639,640,5,6,0,0,640,642,1,0, + 0,0,641,628,1,0,0,0,641,630,1,0,0,0,642,93,1,0,0,0,643,644,3,98, + 49,0,644,95,1,0,0,0,645,646,5,5,0,0,646,659,5,6,0,0,647,648,5,5, + 0,0,648,653,3,98,49,0,649,650,5,1,0,0,650,652,3,98,49,0,651,649, + 1,0,0,0,652,655,1,0,0,0,653,651,1,0,0,0,653,654,1,0,0,0,654,656, + 1,0,0,0,655,653,1,0,0,0,656,657,5,6,0,0,657,659,1,0,0,0,658,645, + 1,0,0,0,658,647,1,0,0,0,659,97,1,0,0,0,660,661,5,151,0,0,661,662, + 5,2,0,0,662,676,5,153,0,0,663,664,5,151,0,0,664,665,5,2,0,0,665, + 676,5,152,0,0,666,667,5,151,0,0,667,668,5,2,0,0,668,676,3,78,39, + 0,669,670,5,151,0,0,670,671,5,2,0,0,671,676,5,155,0,0,672,673,5, + 157,0,0,673,674,5,2,0,0,674,676,3,100,50,0,675,660,1,0,0,0,675,663, + 1,0,0,0,675,666,1,0,0,0,675,669,1,0,0,0,675,672,1,0,0,0,676,99,1, + 0,0,0,677,681,3,96,48,0,678,681,3,102,51,0,679,681,3,104,52,0,680, + 677,1,0,0,0,680,678,1,0,0,0,680,679,1,0,0,0,681,101,1,0,0,0,682, + 683,5,3,0,0,683,696,5,4,0,0,684,685,5,3,0,0,685,690,3,100,50,0,686, + 687,5,1,0,0,687,689,3,100,50,0,688,686,1,0,0,0,689,692,1,0,0,0,690, + 688,1,0,0,0,690,691,1,0,0,0,691,693,1,0,0,0,692,690,1,0,0,0,693, + 694,5,4,0,0,694,696,1,0,0,0,695,682,1,0,0,0,695,684,1,0,0,0,696, + 103,1,0,0,0,697,704,5,159,0,0,698,704,5,158,0,0,699,704,7,1,0,0, + 700,704,5,9,0,0,701,704,5,156,0,0,702,704,3,234,117,0,703,697,1, + 0,0,0,703,698,1,0,0,0,703,699,1,0,0,0,703,700,1,0,0,0,703,701,1, + 0,0,0,703,702,1,0,0,0,704,105,1,0,0,0,705,706,5,134,0,0,706,707, + 5,2,0,0,707,712,3,110,55,0,708,709,5,134,0,0,709,710,5,2,0,0,710, + 712,5,156,0,0,711,705,1,0,0,0,711,708,1,0,0,0,712,107,1,0,0,0,713, + 714,5,133,0,0,714,715,5,2,0,0,715,716,3,114,57,0,716,109,1,0,0,0, + 717,718,5,5,0,0,718,731,5,6,0,0,719,720,5,5,0,0,720,725,3,112,56, + 0,721,722,5,1,0,0,722,724,3,112,56,0,723,721,1,0,0,0,724,727,1,0, + 0,0,725,723,1,0,0,0,725,726,1,0,0,0,726,728,1,0,0,0,727,725,1,0, + 0,0,728,729,5,6,0,0,729,731,1,0,0,0,730,717,1,0,0,0,730,719,1,0, + 0,0,731,111,1,0,0,0,732,733,3,234,117,0,733,734,5,2,0,0,734,735, + 3,114,57,0,735,113,1,0,0,0,736,740,3,110,55,0,737,740,3,116,58,0, + 738,740,3,118,59,0,739,736,1,0,0,0,739,737,1,0,0,0,739,738,1,0,0, + 0,740,115,1,0,0,0,741,742,5,3,0,0,742,755,5,4,0,0,743,744,5,3,0, + 0,744,749,3,114,57,0,745,746,5,1,0,0,746,748,3,114,57,0,747,745, + 1,0,0,0,748,751,1,0,0,0,749,747,1,0,0,0,749,750,1,0,0,0,750,752, + 1,0,0,0,751,749,1,0,0,0,752,753,5,4,0,0,753,755,1,0,0,0,754,741, + 1,0,0,0,754,743,1,0,0,0,755,117,1,0,0,0,756,763,5,159,0,0,757,763, + 5,158,0,0,758,763,7,1,0,0,759,763,5,9,0,0,760,763,5,156,0,0,761, + 763,3,234,117,0,762,756,1,0,0,0,762,757,1,0,0,0,762,758,1,0,0,0, + 762,759,1,0,0,0,762,760,1,0,0,0,762,761,1,0,0,0,763,119,1,0,0,0, + 764,765,5,99,0,0,765,766,5,2,0,0,766,767,3,80,40,0,767,121,1,0,0, + 0,768,769,7,2,0,0,769,123,1,0,0,0,770,771,5,24,0,0,771,772,5,2,0, + 0,772,773,5,3,0,0,773,778,3,126,63,0,774,775,5,1,0,0,775,777,3,126, + 63,0,776,774,1,0,0,0,777,780,1,0,0,0,778,776,1,0,0,0,778,779,1,0, + 0,0,779,781,1,0,0,0,780,778,1,0,0,0,781,782,5,4,0,0,782,125,1,0, + 0,0,783,784,5,5,0,0,784,787,3,128,64,0,785,786,5,1,0,0,786,788,3, + 128,64,0,787,785,1,0,0,0,788,789,1,0,0,0,789,787,1,0,0,0,789,790, + 1,0,0,0,790,791,1,0,0,0,791,792,5,6,0,0,792,805,1,0,0,0,793,794, + 5,5,0,0,794,799,3,130,65,0,795,796,5,1,0,0,796,798,3,130,65,0,797, + 795,1,0,0,0,798,801,1,0,0,0,799,797,1,0,0,0,799,800,1,0,0,0,800, + 802,1,0,0,0,801,799,1,0,0,0,802,803,5,6,0,0,803,805,1,0,0,0,804, + 783,1,0,0,0,804,793,1,0,0,0,805,127,1,0,0,0,806,812,3,134,67,0,807, + 812,3,136,68,0,808,812,3,26,13,0,809,812,3,90,45,0,810,812,3,8,4, + 0,811,806,1,0,0,0,811,807,1,0,0,0,811,808,1,0,0,0,811,809,1,0,0, + 0,811,810,1,0,0,0,812,129,1,0,0,0,813,818,3,132,66,0,814,818,3,26, + 13,0,815,818,3,90,45,0,816,818,3,8,4,0,817,813,1,0,0,0,817,814,1, + 0,0,0,817,815,1,0,0,0,817,816,1,0,0,0,818,131,1,0,0,0,819,820,3, + 220,110,0,820,833,5,2,0,0,821,834,3,126,63,0,822,823,5,3,0,0,823, + 828,3,126,63,0,824,825,5,1,0,0,825,827,3,126,63,0,826,824,1,0,0, + 0,827,830,1,0,0,0,828,826,1,0,0,0,828,829,1,0,0,0,829,831,1,0,0, + 0,830,828,1,0,0,0,831,832,5,4,0,0,832,834,1,0,0,0,833,821,1,0,0, + 0,833,822,1,0,0,0,834,133,1,0,0,0,835,836,5,26,0,0,836,837,5,2,0, + 0,837,845,5,153,0,0,838,839,5,26,0,0,839,840,5,2,0,0,840,845,3,78, + 39,0,841,842,5,26,0,0,842,843,5,2,0,0,843,845,5,152,0,0,844,835, + 1,0,0,0,844,838,1,0,0,0,844,841,1,0,0,0,845,135,1,0,0,0,846,847, + 5,25,0,0,847,848,5,2,0,0,848,861,7,1,0,0,849,850,5,25,0,0,850,851, + 5,2,0,0,851,861,5,156,0,0,852,853,3,218,109,0,853,854,5,2,0,0,854, + 855,3,78,39,0,855,861,1,0,0,0,856,857,3,218,109,0,857,858,5,2,0, + 0,858,859,3,232,116,0,859,861,1,0,0,0,860,846,1,0,0,0,860,849,1, + 0,0,0,860,852,1,0,0,0,860,856,1,0,0,0,861,137,1,0,0,0,862,863,5, + 28,0,0,863,864,5,2,0,0,864,865,5,3,0,0,865,870,3,2,1,0,866,867,5, + 1,0,0,867,869,3,2,1,0,868,866,1,0,0,0,869,872,1,0,0,0,870,868,1, + 0,0,0,870,871,1,0,0,0,871,873,1,0,0,0,872,870,1,0,0,0,873,874,5, + 4,0,0,874,139,1,0,0,0,875,876,5,85,0,0,876,877,5,2,0,0,877,878,5, + 5,0,0,878,883,3,142,71,0,879,880,5,1,0,0,880,882,3,142,71,0,881, + 879,1,0,0,0,882,885,1,0,0,0,883,881,1,0,0,0,883,884,1,0,0,0,884, + 886,1,0,0,0,885,883,1,0,0,0,886,887,5,6,0,0,887,141,1,0,0,0,888, + 893,3,144,72,0,889,893,3,6,3,0,890,893,3,16,8,0,891,893,3,8,4,0, + 892,888,1,0,0,0,892,889,1,0,0,0,892,890,1,0,0,0,892,891,1,0,0,0, + 893,143,1,0,0,0,894,895,5,79,0,0,895,896,5,2,0,0,896,897,5,5,0,0, + 897,902,3,146,73,0,898,899,5,1,0,0,899,901,3,146,73,0,900,898,1, + 0,0,0,901,904,1,0,0,0,902,900,1,0,0,0,902,903,1,0,0,0,903,905,1, + 0,0,0,904,902,1,0,0,0,905,906,5,6,0,0,906,145,1,0,0,0,907,910,3, + 148,74,0,908,910,3,152,76,0,909,907,1,0,0,0,909,908,1,0,0,0,910, + 147,1,0,0,0,911,912,5,80,0,0,912,913,5,2,0,0,913,914,3,150,75,0, + 914,149,1,0,0,0,915,916,7,3,0,0,916,151,1,0,0,0,917,918,5,83,0,0, + 918,919,5,2,0,0,919,920,3,154,77,0,920,153,1,0,0,0,921,922,5,84, + 0,0,922,155,1,0,0,0,923,924,5,86,0,0,924,925,5,2,0,0,925,926,5,5, + 0,0,926,931,3,158,79,0,927,928,5,1,0,0,928,930,3,158,79,0,929,927, + 1,0,0,0,930,933,1,0,0,0,931,929,1,0,0,0,931,932,1,0,0,0,932,934, + 1,0,0,0,933,931,1,0,0,0,934,935,5,6,0,0,935,157,1,0,0,0,936,941, + 3,6,3,0,937,941,3,16,8,0,938,941,3,8,4,0,939,941,3,144,72,0,940, + 936,1,0,0,0,940,937,1,0,0,0,940,938,1,0,0,0,940,939,1,0,0,0,941, + 159,1,0,0,0,942,943,5,87,0,0,943,944,5,2,0,0,944,945,3,80,40,0,945, + 161,1,0,0,0,946,947,5,100,0,0,947,948,5,2,0,0,948,949,5,5,0,0,949, + 954,3,164,82,0,950,951,5,1,0,0,951,953,3,164,82,0,952,950,1,0,0, + 0,953,956,1,0,0,0,954,952,1,0,0,0,954,955,1,0,0,0,955,957,1,0,0, + 0,956,954,1,0,0,0,957,958,5,6,0,0,958,163,1,0,0,0,959,964,3,28,14, + 0,960,964,3,166,83,0,961,964,3,66,33,0,962,964,3,106,53,0,963,959, + 1,0,0,0,963,960,1,0,0,0,963,961,1,0,0,0,963,962,1,0,0,0,964,165, + 1,0,0,0,965,966,5,101,0,0,966,967,5,2,0,0,967,968,5,5,0,0,968,973, + 3,168,84,0,969,970,5,1,0,0,970,972,3,168,84,0,971,969,1,0,0,0,972, + 975,1,0,0,0,973,971,1,0,0,0,973,974,1,0,0,0,974,976,1,0,0,0,975, + 973,1,0,0,0,976,977,5,6,0,0,977,167,1,0,0,0,978,984,3,170,85,0,979, + 984,3,172,86,0,980,984,3,174,87,0,981,984,3,176,88,0,982,984,3,178, + 89,0,983,978,1,0,0,0,983,979,1,0,0,0,983,980,1,0,0,0,983,981,1,0, + 0,0,983,982,1,0,0,0,984,169,1,0,0,0,985,986,5,102,0,0,986,987,5, + 2,0,0,987,988,3,234,117,0,988,171,1,0,0,0,989,990,5,103,0,0,990, + 991,5,2,0,0,991,992,3,234,117,0,992,173,1,0,0,0,993,994,5,104,0, + 0,994,995,5,2,0,0,995,996,5,3,0,0,996,1001,3,234,117,0,997,998,5, + 1,0,0,998,1000,3,234,117,0,999,997,1,0,0,0,1000,1003,1,0,0,0,1001, + 999,1,0,0,0,1001,1002,1,0,0,0,1002,1004,1,0,0,0,1003,1001,1,0,0, + 0,1004,1005,5,4,0,0,1005,175,1,0,0,0,1006,1007,5,105,0,0,1007,1008, + 5,2,0,0,1008,1013,5,156,0,0,1009,1010,5,105,0,0,1010,1011,5,2,0, + 0,1011,1013,5,158,0,0,1012,1006,1,0,0,0,1012,1009,1,0,0,0,1013,177, + 1,0,0,0,1014,1015,5,106,0,0,1015,1016,5,2,0,0,1016,1021,3,78,39, + 0,1017,1018,5,106,0,0,1018,1019,5,2,0,0,1019,1021,5,153,0,0,1020, + 1014,1,0,0,0,1020,1017,1,0,0,0,1021,179,1,0,0,0,1022,1023,5,107, + 0,0,1023,1024,5,2,0,0,1024,1029,5,156,0,0,1025,1026,5,107,0,0,1026, + 1027,5,2,0,0,1027,1029,5,158,0,0,1028,1022,1,0,0,0,1028,1025,1,0, + 0,0,1029,181,1,0,0,0,1030,1031,5,108,0,0,1031,1032,5,2,0,0,1032, + 1037,3,78,39,0,1033,1034,5,108,0,0,1034,1035,5,2,0,0,1035,1037,5, + 153,0,0,1036,1030,1,0,0,0,1036,1033,1,0,0,0,1037,183,1,0,0,0,1038, + 1039,5,109,0,0,1039,1040,5,2,0,0,1040,1045,5,156,0,0,1041,1042,5, + 109,0,0,1042,1043,5,2,0,0,1043,1045,5,159,0,0,1044,1038,1,0,0,0, + 1044,1041,1,0,0,0,1045,185,1,0,0,0,1046,1047,5,110,0,0,1047,1048, + 5,2,0,0,1048,1053,3,78,39,0,1049,1050,5,110,0,0,1050,1051,5,2,0, + 0,1051,1053,5,153,0,0,1052,1046,1,0,0,0,1052,1049,1,0,0,0,1053,187, + 1,0,0,0,1054,1055,5,111,0,0,1055,1056,5,2,0,0,1056,1057,3,234,117, + 0,1057,189,1,0,0,0,1058,1059,5,112,0,0,1059,1060,5,2,0,0,1060,1061, + 5,5,0,0,1061,1066,3,192,96,0,1062,1063,5,1,0,0,1063,1065,3,192,96, + 0,1064,1062,1,0,0,0,1065,1068,1,0,0,0,1066,1064,1,0,0,0,1066,1067, + 1,0,0,0,1067,1069,1,0,0,0,1068,1066,1,0,0,0,1069,1070,5,6,0,0,1070, + 191,1,0,0,0,1071,1074,3,28,14,0,1072,1074,3,66,33,0,1073,1071,1, + 0,0,0,1073,1072,1,0,0,0,1074,193,1,0,0,0,1075,1076,5,119,0,0,1076, + 1077,5,2,0,0,1077,1086,5,3,0,0,1078,1083,3,196,98,0,1079,1080,5, + 1,0,0,1080,1082,3,196,98,0,1081,1079,1,0,0,0,1082,1085,1,0,0,0,1083, + 1081,1,0,0,0,1083,1084,1,0,0,0,1084,1087,1,0,0,0,1085,1083,1,0,0, + 0,1086,1078,1,0,0,0,1086,1087,1,0,0,0,1087,1088,1,0,0,0,1088,1089, + 5,4,0,0,1089,195,1,0,0,0,1090,1091,5,5,0,0,1091,1096,3,198,99,0, + 1092,1093,5,1,0,0,1093,1095,3,198,99,0,1094,1092,1,0,0,0,1095,1098, + 1,0,0,0,1096,1094,1,0,0,0,1096,1097,1,0,0,0,1097,1099,1,0,0,0,1098, + 1096,1,0,0,0,1099,1100,5,6,0,0,1100,197,1,0,0,0,1101,1109,3,200, + 100,0,1102,1109,3,202,101,0,1103,1109,3,204,102,0,1104,1109,3,206, + 103,0,1105,1109,3,208,104,0,1106,1109,3,210,105,0,1107,1109,3,8, + 4,0,1108,1101,1,0,0,0,1108,1102,1,0,0,0,1108,1103,1,0,0,0,1108,1104, + 1,0,0,0,1108,1105,1,0,0,0,1108,1106,1,0,0,0,1108,1107,1,0,0,0,1109, + 199,1,0,0,0,1110,1111,5,120,0,0,1111,1112,5,2,0,0,1112,1113,5,3, + 0,0,1113,1118,3,224,112,0,1114,1115,5,1,0,0,1115,1117,3,224,112, + 0,1116,1114,1,0,0,0,1117,1120,1,0,0,0,1118,1116,1,0,0,0,1118,1119, + 1,0,0,0,1119,1121,1,0,0,0,1120,1118,1,0,0,0,1121,1122,5,4,0,0,1122, + 201,1,0,0,0,1123,1124,5,121,0,0,1124,1125,5,2,0,0,1125,1126,5,158, + 0,0,1126,203,1,0,0,0,1127,1128,5,122,0,0,1128,1129,5,2,0,0,1129, + 1130,5,158,0,0,1130,205,1,0,0,0,1131,1132,5,123,0,0,1132,1133,5, + 2,0,0,1133,1134,7,4,0,0,1134,207,1,0,0,0,1135,1136,5,124,0,0,1136, + 1137,5,2,0,0,1137,1138,5,158,0,0,1138,209,1,0,0,0,1139,1140,5,125, + 0,0,1140,1141,5,2,0,0,1141,1142,7,5,0,0,1142,211,1,0,0,0,1143,1144, + 5,128,0,0,1144,1145,5,2,0,0,1145,1154,5,3,0,0,1146,1151,3,214,107, + 0,1147,1148,5,1,0,0,1148,1150,3,214,107,0,1149,1147,1,0,0,0,1150, + 1153,1,0,0,0,1151,1149,1,0,0,0,1151,1152,1,0,0,0,1152,1155,1,0,0, + 0,1153,1151,1,0,0,0,1154,1146,1,0,0,0,1154,1155,1,0,0,0,1155,1156, + 1,0,0,0,1156,1157,5,4,0,0,1157,213,1,0,0,0,1158,1159,5,5,0,0,1159, + 1164,3,216,108,0,1160,1161,5,1,0,0,1161,1163,3,216,108,0,1162,1160, + 1,0,0,0,1163,1166,1,0,0,0,1164,1162,1,0,0,0,1164,1165,1,0,0,0,1165, + 1167,1,0,0,0,1166,1164,1,0,0,0,1167,1168,5,6,0,0,1168,215,1,0,0, + 0,1169,1176,3,200,100,0,1170,1176,3,34,17,0,1171,1176,3,26,13,0, + 1172,1176,3,90,45,0,1173,1176,3,108,54,0,1174,1176,3,8,4,0,1175, + 1169,1,0,0,0,1175,1170,1,0,0,0,1175,1171,1,0,0,0,1175,1172,1,0,0, + 0,1175,1173,1,0,0,0,1175,1174,1,0,0,0,1176,217,1,0,0,0,1177,1178, + 7,6,0,0,1178,219,1,0,0,0,1179,1180,7,7,0,0,1180,221,1,0,0,0,1181, + 1182,7,8,0,0,1182,223,1,0,0,0,1183,1186,3,222,111,0,1184,1186,3, + 234,117,0,1185,1183,1,0,0,0,1185,1184,1,0,0,0,1186,225,1,0,0,0,1187, + 1188,5,5,0,0,1188,1193,3,228,114,0,1189,1190,5,1,0,0,1190,1192,3, + 228,114,0,1191,1189,1,0,0,0,1192,1195,1,0,0,0,1193,1191,1,0,0,0, + 1193,1194,1,0,0,0,1194,1196,1,0,0,0,1195,1193,1,0,0,0,1196,1197, + 5,6,0,0,1197,1201,1,0,0,0,1198,1199,5,5,0,0,1199,1201,5,6,0,0,1200, + 1187,1,0,0,0,1200,1198,1,0,0,0,1201,227,1,0,0,0,1202,1203,3,234, + 117,0,1203,1204,5,2,0,0,1204,1205,3,232,116,0,1205,229,1,0,0,0,1206, + 1207,5,3,0,0,1207,1212,3,232,116,0,1208,1209,5,1,0,0,1209,1211,3, + 232,116,0,1210,1208,1,0,0,0,1211,1214,1,0,0,0,1212,1210,1,0,0,0, + 1212,1213,1,0,0,0,1213,1215,1,0,0,0,1214,1212,1,0,0,0,1215,1216, + 5,4,0,0,1216,1220,1,0,0,0,1217,1218,5,3,0,0,1218,1220,5,4,0,0,1219, + 1206,1,0,0,0,1219,1217,1,0,0,0,1220,231,1,0,0,0,1221,1231,5,159, + 0,0,1222,1231,5,158,0,0,1223,1231,5,7,0,0,1224,1231,5,8,0,0,1225, + 1231,5,9,0,0,1226,1231,3,228,114,0,1227,1231,3,230,115,0,1228,1231, + 3,226,113,0,1229,1231,3,234,117,0,1230,1221,1,0,0,0,1230,1222,1, + 0,0,0,1230,1223,1,0,0,0,1230,1224,1,0,0,0,1230,1225,1,0,0,0,1230, + 1226,1,0,0,0,1230,1227,1,0,0,0,1230,1228,1,0,0,0,1230,1229,1,0,0, + 0,1231,233,1,0,0,0,1232,1233,7,9,0,0,1233,235,1,0,0,0,94,245,256, + 321,331,348,375,377,387,399,401,417,431,439,453,461,469,477,485, + 493,504,512,520,536,544,552,560,570,577,595,603,610,615,622,636, + 641,653,658,675,680,690,695,703,711,725,730,739,749,754,762,778, + 789,799,804,811,817,828,833,844,860,870,883,892,902,909,931,940, + 954,963,973,983,1001,1012,1020,1028,1036,1044,1052,1066,1073,1083, + 1086,1096,1108,1118,1151,1154,1164,1175,1185,1193,1200,1212,1219, + 1230 ] class ASLParser ( Parser ): @@ -3126,13 +3129,41 @@ def accept(self, visitor:ParseTreeVisitor): return visitor.visitChildren(self) + class Error_path_decl_contextContext(Error_path_declContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a ASLParser.Error_path_declContext + super().__init__(parser) + self.copyFrom(ctx) + + def ERRORPATH(self): + return self.getToken(ASLParser.ERRORPATH, 0) + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + def STRINGPATHCONTEXTOBJ(self): + return self.getToken(ASLParser.STRINGPATHCONTEXTOBJ, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterError_path_decl_context" ): + listener.enterError_path_decl_context(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitError_path_decl_context" ): + listener.exitError_path_decl_context(self) + + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitError_path_decl_context" ): + return visitor.visitError_path_decl_context(self) + else: + return visitor.visitChildren(self) + + def error_path_decl(self): localctx = ASLParser.Error_path_declContext(self, self._ctx, self.state) self.enterRule(localctx, 44, self.RULE_error_path_decl) try: - self.state = 428 + self.state = 431 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,11,self._ctx) if la_ == 1: @@ -3158,13 +3189,24 @@ def error_path_decl(self): pass elif la_ == 3: - localctx = ASLParser.Error_path_decl_intrinsicContext(self, localctx) + localctx = ASLParser.Error_path_decl_contextContext(self, localctx) self.enterOuterAlt(localctx, 3) self.state = 425 self.match(ASLParser.ERRORPATH) self.state = 426 self.match(ASLParser.COLON) self.state = 427 + self.match(ASLParser.STRINGPATHCONTEXTOBJ) + pass + + elif la_ == 4: + localctx = ASLParser.Error_path_decl_intrinsicContext(self, localctx) + self.enterOuterAlt(localctx, 4) + self.state = 428 + self.match(ASLParser.ERRORPATH) + self.state = 429 + self.match(ASLParser.COLON) + self.state = 430 self.match(ASLParser.STRINGINTRINSICFUNC) pass @@ -3258,28 +3300,28 @@ def cause_decl(self): localctx = ASLParser.Cause_declContext(self, self._ctx, self.state) self.enterRule(localctx, 46, self.RULE_cause_decl) try: - self.state = 436 + self.state = 439 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,12,self._ctx) if la_ == 1: localctx = ASLParser.Cause_jsonataContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 430 + self.state = 433 self.match(ASLParser.CAUSE) - self.state = 431 + self.state = 434 self.match(ASLParser.COLON) - self.state = 432 + self.state = 435 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 2: localctx = ASLParser.Cause_stringContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 433 + self.state = 436 self.match(ASLParser.CAUSE) - self.state = 434 + self.state = 437 self.match(ASLParser.COLON) - self.state = 435 + self.state = 438 self.keyword_or_string() pass @@ -3338,6 +3380,34 @@ def accept(self, visitor:ParseTreeVisitor): return visitor.visitChildren(self) + class Cause_path_decl_contextContext(Cause_path_declContext): + + def __init__(self, parser, ctx:ParserRuleContext): # actually a ASLParser.Cause_path_declContext + super().__init__(parser) + self.copyFrom(ctx) + + def CAUSEPATH(self): + return self.getToken(ASLParser.CAUSEPATH, 0) + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + def STRINGPATHCONTEXTOBJ(self): + return self.getToken(ASLParser.STRINGPATHCONTEXTOBJ, 0) + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterCause_path_decl_context" ): + listener.enterCause_path_decl_context(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitCause_path_decl_context" ): + listener.exitCause_path_decl_context(self) + + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitCause_path_decl_context" ): + return visitor.visitCause_path_decl_context(self) + else: + return visitor.visitChildren(self) + + class Cause_path_decl_intrinsicContext(Cause_path_declContext): def __init__(self, parser, ctx:ParserRuleContext): # actually a ASLParser.Cause_path_declContext @@ -3401,39 +3471,50 @@ def cause_path_decl(self): localctx = ASLParser.Cause_path_declContext(self, self._ctx, self.state) self.enterRule(localctx, 48, self.RULE_cause_path_decl) try: - self.state = 447 + self.state = 453 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,13,self._ctx) if la_ == 1: localctx = ASLParser.Cause_path_decl_varContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 438 + self.state = 441 self.match(ASLParser.CAUSEPATH) - self.state = 439 + self.state = 442 self.match(ASLParser.COLON) - self.state = 440 + self.state = 443 self.variable_sample() pass elif la_ == 2: localctx = ASLParser.Cause_path_decl_pathContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 441 + self.state = 444 self.match(ASLParser.CAUSEPATH) - self.state = 442 + self.state = 445 self.match(ASLParser.COLON) - self.state = 443 + self.state = 446 self.match(ASLParser.STRINGPATH) pass elif la_ == 3: - localctx = ASLParser.Cause_path_decl_intrinsicContext(self, localctx) + localctx = ASLParser.Cause_path_decl_contextContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 444 + self.state = 447 self.match(ASLParser.CAUSEPATH) - self.state = 445 + self.state = 448 self.match(ASLParser.COLON) - self.state = 446 + self.state = 449 + self.match(ASLParser.STRINGPATHCONTEXTOBJ) + pass + + elif la_ == 4: + localctx = ASLParser.Cause_path_decl_intrinsicContext(self, localctx) + self.enterOuterAlt(localctx, 4) + self.state = 450 + self.match(ASLParser.CAUSEPATH) + self.state = 451 + self.match(ASLParser.COLON) + self.state = 452 self.match(ASLParser.STRINGINTRINSICFUNC) pass @@ -3526,28 +3607,28 @@ def seconds_decl(self): localctx = ASLParser.Seconds_declContext(self, self._ctx, self.state) self.enterRule(localctx, 50, self.RULE_seconds_decl) try: - self.state = 455 + self.state = 461 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,14,self._ctx) if la_ == 1: localctx = ASLParser.Seconds_jsonataContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 449 + self.state = 455 self.match(ASLParser.SECONDS) - self.state = 450 + self.state = 456 self.match(ASLParser.COLON) - self.state = 451 + self.state = 457 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 2: localctx = ASLParser.Seconds_intContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 452 + self.state = 458 self.match(ASLParser.SECONDS) - self.state = 453 + self.state = 459 self.match(ASLParser.COLON) - self.state = 454 + self.state = 460 self.match(ASLParser.INT) pass @@ -3642,28 +3723,28 @@ def seconds_path_decl(self): localctx = ASLParser.Seconds_path_declContext(self, self._ctx, self.state) self.enterRule(localctx, 52, self.RULE_seconds_path_decl) try: - self.state = 463 + self.state = 469 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,15,self._ctx) if la_ == 1: localctx = ASLParser.Seconds_path_decl_varContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 457 + self.state = 463 self.match(ASLParser.SECONDSPATH) - self.state = 458 + self.state = 464 self.match(ASLParser.COLON) - self.state = 459 + self.state = 465 self.variable_sample() pass elif la_ == 2: localctx = ASLParser.Seconds_path_decl_valueContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 460 + self.state = 466 self.match(ASLParser.SECONDSPATH) - self.state = 461 + self.state = 467 self.match(ASLParser.COLON) - self.state = 462 + self.state = 468 self.keyword_or_string() pass @@ -3757,28 +3838,28 @@ def timestamp_decl(self): localctx = ASLParser.Timestamp_declContext(self, self._ctx, self.state) self.enterRule(localctx, 54, self.RULE_timestamp_decl) try: - self.state = 471 + self.state = 477 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,16,self._ctx) if la_ == 1: localctx = ASLParser.Timestamp_jsonataContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 465 + self.state = 471 self.match(ASLParser.TIMESTAMP) - self.state = 466 + self.state = 472 self.match(ASLParser.COLON) - self.state = 467 + self.state = 473 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 2: localctx = ASLParser.Timestamp_stringContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 468 + self.state = 474 self.match(ASLParser.TIMESTAMP) - self.state = 469 + self.state = 475 self.match(ASLParser.COLON) - self.state = 470 + self.state = 476 self.keyword_or_string() pass @@ -3873,28 +3954,28 @@ def timestamp_path_decl(self): localctx = ASLParser.Timestamp_path_declContext(self, self._ctx, self.state) self.enterRule(localctx, 56, self.RULE_timestamp_path_decl) try: - self.state = 479 + self.state = 485 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,17,self._ctx) if la_ == 1: localctx = ASLParser.Timestamp_path_decl_varContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 473 + self.state = 479 self.match(ASLParser.TIMESTAMPPATH) - self.state = 474 + self.state = 480 self.match(ASLParser.COLON) - self.state = 475 + self.state = 481 self.variable_sample() pass elif la_ == 2: localctx = ASLParser.Timestamp_path_decl_valueContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 476 + self.state = 482 self.match(ASLParser.TIMESTAMPPATH) - self.state = 477 + self.state = 483 self.match(ASLParser.COLON) - self.state = 478 + self.state = 484 self.keyword_or_string() pass @@ -3988,28 +4069,28 @@ def items_decl(self): localctx = ASLParser.Items_declContext(self, self._ctx, self.state) self.enterRule(localctx, 58, self.RULE_items_decl) try: - self.state = 487 + self.state = 493 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,18,self._ctx) if la_ == 1: localctx = ASLParser.Items_arrayContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 481 + self.state = 487 self.match(ASLParser.ITEMS) - self.state = 482 + self.state = 488 self.match(ASLParser.COLON) - self.state = 483 + self.state = 489 self.jsonata_template_value_array() pass elif la_ == 2: localctx = ASLParser.Items_jsonataContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 484 + self.state = 490 self.match(ASLParser.ITEMS) - self.state = 485 + self.state = 491 self.match(ASLParser.COLON) - self.state = 486 + self.state = 492 self.match(ASLParser.STRINGJSONATA) pass @@ -4132,39 +4213,39 @@ def items_path_decl(self): localctx = ASLParser.Items_path_declContext(self, self._ctx, self.state) self.enterRule(localctx, 60, self.RULE_items_path_decl) try: - self.state = 498 + self.state = 504 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,19,self._ctx) if la_ == 1: localctx = ASLParser.Items_path_decl_path_context_objectContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 489 + self.state = 495 self.match(ASLParser.ITEMSPATH) - self.state = 490 + self.state = 496 self.match(ASLParser.COLON) - self.state = 491 + self.state = 497 self.match(ASLParser.STRINGPATHCONTEXTOBJ) pass elif la_ == 2: localctx = ASLParser.Items_path_decl_path_varContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 492 + self.state = 498 self.match(ASLParser.ITEMSPATH) - self.state = 493 + self.state = 499 self.match(ASLParser.COLON) - self.state = 494 + self.state = 500 self.variable_sample() pass elif la_ == 3: localctx = ASLParser.Items_path_decl_pathContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 495 + self.state = 501 self.match(ASLParser.ITEMSPATH) - self.state = 496 + self.state = 502 self.match(ASLParser.COLON) - self.state = 497 + self.state = 503 self.keyword_or_string() pass @@ -4257,28 +4338,28 @@ def max_concurrency_decl(self): localctx = ASLParser.Max_concurrency_declContext(self, self._ctx, self.state) self.enterRule(localctx, 62, self.RULE_max_concurrency_decl) try: - self.state = 506 + self.state = 512 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,20,self._ctx) if la_ == 1: localctx = ASLParser.Max_concurrency_jsonataContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 500 + self.state = 506 self.match(ASLParser.MAXCONCURRENCY) - self.state = 501 + self.state = 507 self.match(ASLParser.COLON) - self.state = 502 + self.state = 508 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 2: localctx = ASLParser.Max_concurrency_intContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 503 + self.state = 509 self.match(ASLParser.MAXCONCURRENCY) - self.state = 504 + self.state = 510 self.match(ASLParser.COLON) - self.state = 505 + self.state = 511 self.match(ASLParser.INT) pass @@ -4372,28 +4453,28 @@ def max_concurrency_path_decl(self): localctx = ASLParser.Max_concurrency_path_declContext(self, self._ctx, self.state) self.enterRule(localctx, 64, self.RULE_max_concurrency_path_decl) try: - self.state = 514 + self.state = 520 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,21,self._ctx) if la_ == 1: localctx = ASLParser.Max_concurrency_path_varContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 508 + self.state = 514 self.match(ASLParser.MAXCONCURRENCYPATH) - self.state = 509 + self.state = 515 self.match(ASLParser.COLON) - self.state = 510 + self.state = 516 self.variable_sample() pass elif la_ == 2: localctx = ASLParser.Max_concurrency_pathContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 511 + self.state = 517 self.match(ASLParser.MAXCONCURRENCYPATH) - self.state = 512 + self.state = 518 self.match(ASLParser.COLON) - self.state = 513 + self.state = 519 self.match(ASLParser.STRINGPATH) pass @@ -4450,11 +4531,11 @@ def parameters_decl(self): self.enterRule(localctx, 66, self.RULE_parameters_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 516 + self.state = 522 self.match(ASLParser.PARAMETERS) - self.state = 517 + self.state = 523 self.match(ASLParser.COLON) - self.state = 518 + self.state = 524 self.payload_tmpl_decl() except RecognitionException as re: localctx.exception = re @@ -4508,11 +4589,11 @@ def credentials_decl(self): self.enterRule(localctx, 68, self.RULE_credentials_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 520 + self.state = 526 self.match(ASLParser.CREDENTIALS) - self.state = 521 + self.state = 527 self.match(ASLParser.COLON) - self.state = 522 + self.state = 528 self.payload_tmpl_decl() except RecognitionException as re: localctx.exception = re @@ -4602,28 +4683,28 @@ def timeout_seconds_decl(self): localctx = ASLParser.Timeout_seconds_declContext(self, self._ctx, self.state) self.enterRule(localctx, 70, self.RULE_timeout_seconds_decl) try: - self.state = 530 + self.state = 536 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,22,self._ctx) if la_ == 1: localctx = ASLParser.Timeout_seconds_jsonataContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 524 + self.state = 530 self.match(ASLParser.TIMEOUTSECONDS) - self.state = 525 + self.state = 531 self.match(ASLParser.COLON) - self.state = 526 + self.state = 532 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 2: localctx = ASLParser.Timeout_seconds_intContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 527 + self.state = 533 self.match(ASLParser.TIMEOUTSECONDS) - self.state = 528 + self.state = 534 self.match(ASLParser.COLON) - self.state = 529 + self.state = 535 self.match(ASLParser.INT) pass @@ -4717,28 +4798,28 @@ def timeout_seconds_path_decl(self): localctx = ASLParser.Timeout_seconds_path_declContext(self, self._ctx, self.state) self.enterRule(localctx, 72, self.RULE_timeout_seconds_path_decl) try: - self.state = 538 + self.state = 544 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,23,self._ctx) if la_ == 1: localctx = ASLParser.Timeout_seconds_path_decl_varContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 532 + self.state = 538 self.match(ASLParser.TIMEOUTSECONDSPATH) - self.state = 533 + self.state = 539 self.match(ASLParser.COLON) - self.state = 534 + self.state = 540 self.variable_sample() pass elif la_ == 2: localctx = ASLParser.Timeout_seconds_path_decl_pathContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 535 + self.state = 541 self.match(ASLParser.TIMEOUTSECONDSPATH) - self.state = 536 + self.state = 542 self.match(ASLParser.COLON) - self.state = 537 + self.state = 543 self.match(ASLParser.STRINGPATH) pass @@ -4831,28 +4912,28 @@ def heartbeat_seconds_decl(self): localctx = ASLParser.Heartbeat_seconds_declContext(self, self._ctx, self.state) self.enterRule(localctx, 74, self.RULE_heartbeat_seconds_decl) try: - self.state = 546 + self.state = 552 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,24,self._ctx) if la_ == 1: localctx = ASLParser.Heartbeat_seconds_jsonataContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 540 + self.state = 546 self.match(ASLParser.HEARTBEATSECONDS) - self.state = 541 + self.state = 547 self.match(ASLParser.COLON) - self.state = 542 + self.state = 548 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 2: localctx = ASLParser.Heartbeat_seconds_intContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 543 + self.state = 549 self.match(ASLParser.HEARTBEATSECONDS) - self.state = 544 + self.state = 550 self.match(ASLParser.COLON) - self.state = 545 + self.state = 551 self.match(ASLParser.INT) pass @@ -4946,28 +5027,28 @@ def heartbeat_seconds_path_decl(self): localctx = ASLParser.Heartbeat_seconds_path_declContext(self, self._ctx, self.state) self.enterRule(localctx, 76, self.RULE_heartbeat_seconds_path_decl) try: - self.state = 554 + self.state = 560 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,25,self._ctx) if la_ == 1: localctx = ASLParser.Heartbeat_seconds_path_decl_varContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 548 + self.state = 554 self.match(ASLParser.HEARTBEATSECONDSPATH) - self.state = 549 + self.state = 555 self.match(ASLParser.COLON) - self.state = 550 + self.state = 556 self.variable_sample() pass elif la_ == 2: localctx = ASLParser.Heartbeat_seconds_path_decl_pathContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 551 + self.state = 557 self.match(ASLParser.HEARTBEATSECONDSPATH) - self.state = 552 + self.state = 558 self.match(ASLParser.COLON) - self.state = 553 + self.state = 559 self.match(ASLParser.STRINGPATH) pass @@ -5017,7 +5098,7 @@ def variable_sample(self): self.enterRule(localctx, 78, self.RULE_variable_sample) try: self.enterOuterAlt(localctx, 1) - self.state = 556 + self.state = 562 self.match(ASLParser.STRINGVAR) except RecognitionException as re: localctx.exception = re @@ -5080,36 +5161,36 @@ def payload_tmpl_decl(self): self.enterRule(localctx, 80, self.RULE_payload_tmpl_decl) self._la = 0 # Token type try: - self.state = 571 + self.state = 577 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,27,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 558 + self.state = 564 self.match(ASLParser.LBRACE) - self.state = 559 + self.state = 565 self.payload_binding() - self.state = 564 + self.state = 570 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 560 + self.state = 566 self.match(ASLParser.COMMA) - self.state = 561 + self.state = 567 self.payload_binding() - self.state = 566 + self.state = 572 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 567 + self.state = 573 self.match(ASLParser.RBRACE) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 569 + self.state = 575 self.match(ASLParser.LBRACE) - self.state = 570 + self.state = 576 self.match(ASLParser.RBRACE) pass @@ -5289,61 +5370,61 @@ def payload_binding(self): localctx = ASLParser.Payload_bindingContext(self, self._ctx, self.state) self.enterRule(localctx, 82, self.RULE_payload_binding) try: - self.state = 589 + self.state = 595 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,28,self._ctx) if la_ == 1: localctx = ASLParser.Payload_binding_pathContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 573 + self.state = 579 self.match(ASLParser.STRINGDOLLAR) - self.state = 574 + self.state = 580 self.match(ASLParser.COLON) - self.state = 575 + self.state = 581 self.match(ASLParser.STRINGPATH) pass elif la_ == 2: localctx = ASLParser.Payload_binding_path_context_objContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 576 + self.state = 582 self.match(ASLParser.STRINGDOLLAR) - self.state = 577 + self.state = 583 self.match(ASLParser.COLON) - self.state = 578 + self.state = 584 self.match(ASLParser.STRINGPATHCONTEXTOBJ) pass elif la_ == 3: localctx = ASLParser.Payload_binding_intrinsic_funcContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 579 + self.state = 585 self.match(ASLParser.STRINGDOLLAR) - self.state = 580 + self.state = 586 self.match(ASLParser.COLON) - self.state = 581 + self.state = 587 self.match(ASLParser.STRINGINTRINSICFUNC) pass elif la_ == 4: localctx = ASLParser.Payload_binding_varContext(self, localctx) self.enterOuterAlt(localctx, 4) - self.state = 582 + self.state = 588 self.match(ASLParser.STRINGDOLLAR) - self.state = 583 + self.state = 589 self.match(ASLParser.COLON) - self.state = 584 + self.state = 590 self.variable_sample() pass elif la_ == 5: localctx = ASLParser.Payload_binding_valueContext(self, localctx) self.enterOuterAlt(localctx, 5) - self.state = 585 + self.state = 591 self.keyword_or_string() - self.state = 586 + self.state = 592 self.match(ASLParser.COLON) - self.state = 587 + self.state = 593 self.payload_value_decl() pass @@ -5409,36 +5490,36 @@ def payload_arr_decl(self): self.enterRule(localctx, 84, self.RULE_payload_arr_decl) self._la = 0 # Token type try: - self.state = 604 + self.state = 610 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,30,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 591 + self.state = 597 self.match(ASLParser.LBRACK) - self.state = 592 + self.state = 598 self.payload_value_decl() - self.state = 597 + self.state = 603 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 593 + self.state = 599 self.match(ASLParser.COMMA) - self.state = 594 + self.state = 600 self.payload_value_decl() - self.state = 599 + self.state = 605 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 600 + self.state = 606 self.match(ASLParser.RBRACK) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 602 + self.state = 608 self.match(ASLParser.LBRACK) - self.state = 603 + self.state = 609 self.match(ASLParser.RBRACK) pass @@ -5496,22 +5577,22 @@ def payload_value_decl(self): localctx = ASLParser.Payload_value_declContext(self, self._ctx, self.state) self.enterRule(localctx, 86, self.RULE_payload_value_decl) try: - self.state = 609 + self.state = 615 self._errHandler.sync(self) token = self._input.LA(1) if token in [3]: self.enterOuterAlt(localctx, 1) - self.state = 606 + self.state = 612 self.payload_arr_decl() pass elif token in [5]: self.enterOuterAlt(localctx, 2) - self.state = 607 + self.state = 613 self.payload_tmpl_decl() pass elif token in [7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 117, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 132, 133, 134, 135, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159]: self.enterOuterAlt(localctx, 3) - self.state = 608 + self.state = 614 self.payload_value_lit() pass else: @@ -5673,25 +5754,25 @@ def payload_value_lit(self): self.enterRule(localctx, 88, self.RULE_payload_value_lit) self._la = 0 # Token type try: - self.state = 616 + self.state = 622 self._errHandler.sync(self) token = self._input.LA(1) if token in [159]: localctx = ASLParser.Payload_value_floatContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 611 + self.state = 617 self.match(ASLParser.NUMBER) pass elif token in [158]: localctx = ASLParser.Payload_value_intContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 612 + self.state = 618 self.match(ASLParser.INT) pass elif token in [7, 8]: localctx = ASLParser.Payload_value_boolContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 613 + self.state = 619 _la = self._input.LA(1) if not(_la==7 or _la==8): self._errHandler.recoverInline(self) @@ -5702,13 +5783,13 @@ def payload_value_lit(self): elif token in [9]: localctx = ASLParser.Payload_value_nullContext(self, localctx) self.enterOuterAlt(localctx, 4) - self.state = 614 + self.state = 620 self.match(ASLParser.NULL) pass elif token in [10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 117, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 132, 133, 134, 135, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157]: localctx = ASLParser.Payload_value_strContext(self, localctx) self.enterOuterAlt(localctx, 5) - self.state = 615 + self.state = 621 self.keyword_or_string() pass else: @@ -5766,11 +5847,11 @@ def assign_decl(self): self.enterRule(localctx, 90, self.RULE_assign_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 618 + self.state = 624 self.match(ASLParser.ASSIGN) - self.state = 619 + self.state = 625 self.match(ASLParser.COLON) - self.state = 620 + self.state = 626 self.assign_decl_body() except RecognitionException as re: localctx.exception = re @@ -5833,36 +5914,36 @@ def assign_decl_body(self): self.enterRule(localctx, 92, self.RULE_assign_decl_body) self._la = 0 # Token type try: - self.state = 635 + self.state = 641 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,34,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 622 + self.state = 628 self.match(ASLParser.LBRACE) - self.state = 623 + self.state = 629 self.match(ASLParser.RBRACE) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 624 + self.state = 630 self.match(ASLParser.LBRACE) - self.state = 625 + self.state = 631 self.assign_decl_binding() - self.state = 630 + self.state = 636 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 626 + self.state = 632 self.match(ASLParser.COMMA) - self.state = 627 + self.state = 633 self.assign_decl_binding() - self.state = 632 + self.state = 638 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 633 + self.state = 639 self.match(ASLParser.RBRACE) pass @@ -5913,7 +5994,7 @@ def assign_decl_binding(self): self.enterRule(localctx, 94, self.RULE_assign_decl_binding) try: self.enterOuterAlt(localctx, 1) - self.state = 637 + self.state = 643 self.assign_template_binding() except RecognitionException as re: localctx.exception = re @@ -5976,36 +6057,36 @@ def assign_template_value_object(self): self.enterRule(localctx, 96, self.RULE_assign_template_value_object) self._la = 0 # Token type try: - self.state = 652 + self.state = 658 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,36,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 639 + self.state = 645 self.match(ASLParser.LBRACE) - self.state = 640 + self.state = 646 self.match(ASLParser.RBRACE) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 641 + self.state = 647 self.match(ASLParser.LBRACE) - self.state = 642 + self.state = 648 self.assign_template_binding() - self.state = 647 + self.state = 653 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 643 + self.state = 649 self.match(ASLParser.COMMA) - self.state = 644 + self.state = 650 self.assign_template_binding() - self.state = 649 + self.state = 655 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 650 + self.state = 656 self.match(ASLParser.RBRACE) pass @@ -6184,61 +6265,61 @@ def assign_template_binding(self): localctx = ASLParser.Assign_template_bindingContext(self, self._ctx, self.state) self.enterRule(localctx, 98, self.RULE_assign_template_binding) try: - self.state = 669 + self.state = 675 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,37,self._ctx) if la_ == 1: localctx = ASLParser.Assign_template_binding_pathContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 654 + self.state = 660 self.match(ASLParser.STRINGDOLLAR) - self.state = 655 + self.state = 661 self.match(ASLParser.COLON) - self.state = 656 + self.state = 662 self.match(ASLParser.STRINGPATH) pass elif la_ == 2: localctx = ASLParser.Assign_template_binding_path_contextContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 657 + self.state = 663 self.match(ASLParser.STRINGDOLLAR) - self.state = 658 + self.state = 664 self.match(ASLParser.COLON) - self.state = 659 + self.state = 665 self.match(ASLParser.STRINGPATHCONTEXTOBJ) pass elif la_ == 3: localctx = ASLParser.Assign_template_binding_varContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 660 + self.state = 666 self.match(ASLParser.STRINGDOLLAR) - self.state = 661 + self.state = 667 self.match(ASLParser.COLON) - self.state = 662 + self.state = 668 self.variable_sample() pass elif la_ == 4: localctx = ASLParser.Assign_template_binding_intrinsic_funcContext(self, localctx) self.enterOuterAlt(localctx, 4) - self.state = 663 + self.state = 669 self.match(ASLParser.STRINGDOLLAR) - self.state = 664 + self.state = 670 self.match(ASLParser.COLON) - self.state = 665 + self.state = 671 self.match(ASLParser.STRINGINTRINSICFUNC) pass elif la_ == 5: localctx = ASLParser.Assign_template_binding_assign_valueContext(self, localctx) self.enterOuterAlt(localctx, 5) - self.state = 666 + self.state = 672 self.match(ASLParser.STRING) - self.state = 667 + self.state = 673 self.match(ASLParser.COLON) - self.state = 668 + self.state = 674 self.assign_template_value() pass @@ -6296,22 +6377,22 @@ def assign_template_value(self): localctx = ASLParser.Assign_template_valueContext(self, self._ctx, self.state) self.enterRule(localctx, 100, self.RULE_assign_template_value) try: - self.state = 674 + self.state = 680 self._errHandler.sync(self) token = self._input.LA(1) if token in [5]: self.enterOuterAlt(localctx, 1) - self.state = 671 + self.state = 677 self.assign_template_value_object() pass elif token in [3]: self.enterOuterAlt(localctx, 2) - self.state = 672 + self.state = 678 self.assign_template_value_array() pass elif token in [7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 117, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 132, 133, 134, 135, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159]: self.enterOuterAlt(localctx, 3) - self.state = 673 + self.state = 679 self.assign_template_value_terminal() pass else: @@ -6378,36 +6459,36 @@ def assign_template_value_array(self): self.enterRule(localctx, 102, self.RULE_assign_template_value_array) self._la = 0 # Token type try: - self.state = 689 + self.state = 695 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,40,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 676 + self.state = 682 self.match(ASLParser.LBRACK) - self.state = 677 + self.state = 683 self.match(ASLParser.RBRACK) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 678 + self.state = 684 self.match(ASLParser.LBRACK) - self.state = 679 + self.state = 685 self.assign_template_value() - self.state = 684 + self.state = 690 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 680 + self.state = 686 self.match(ASLParser.COMMA) - self.state = 681 + self.state = 687 self.assign_template_value() - self.state = 686 + self.state = 692 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 687 + self.state = 693 self.match(ASLParser.RBRACK) pass @@ -6592,27 +6673,27 @@ def assign_template_value_terminal(self): self.enterRule(localctx, 104, self.RULE_assign_template_value_terminal) self._la = 0 # Token type try: - self.state = 697 + self.state = 703 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,41,self._ctx) if la_ == 1: localctx = ASLParser.Assign_template_value_terminal_floatContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 691 + self.state = 697 self.match(ASLParser.NUMBER) pass elif la_ == 2: localctx = ASLParser.Assign_template_value_terminal_intContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 692 + self.state = 698 self.match(ASLParser.INT) pass elif la_ == 3: localctx = ASLParser.Assign_template_value_terminal_boolContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 693 + self.state = 699 _la = self._input.LA(1) if not(_la==7 or _la==8): self._errHandler.recoverInline(self) @@ -6624,21 +6705,21 @@ def assign_template_value_terminal(self): elif la_ == 4: localctx = ASLParser.Assign_template_value_terminal_nullContext(self, localctx) self.enterOuterAlt(localctx, 4) - self.state = 694 + self.state = 700 self.match(ASLParser.NULL) pass elif la_ == 5: localctx = ASLParser.Assign_template_value_terminal_expressionContext(self, localctx) self.enterOuterAlt(localctx, 5) - self.state = 695 + self.state = 701 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 6: localctx = ASLParser.Assign_template_value_terminal_strContext(self, localctx) self.enterOuterAlt(localctx, 6) - self.state = 696 + self.state = 702 self.keyword_or_string() pass @@ -6732,28 +6813,28 @@ def arguments_decl(self): localctx = ASLParser.Arguments_declContext(self, self._ctx, self.state) self.enterRule(localctx, 106, self.RULE_arguments_decl) try: - self.state = 705 + self.state = 711 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,42,self._ctx) if la_ == 1: localctx = ASLParser.Arguments_objectContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 699 + self.state = 705 self.match(ASLParser.ARGUMENTS) - self.state = 700 + self.state = 706 self.match(ASLParser.COLON) - self.state = 701 + self.state = 707 self.jsonata_template_value_object() pass elif la_ == 2: localctx = ASLParser.Arguments_exprContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 702 + self.state = 708 self.match(ASLParser.ARGUMENTS) - self.state = 703 + self.state = 709 self.match(ASLParser.COLON) - self.state = 704 + self.state = 710 self.match(ASLParser.STRINGJSONATA) pass @@ -6810,11 +6891,11 @@ def output_decl(self): self.enterRule(localctx, 108, self.RULE_output_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 707 + self.state = 713 self.match(ASLParser.OUTPUT) - self.state = 708 + self.state = 714 self.match(ASLParser.COLON) - self.state = 709 + self.state = 715 self.jsonata_template_value() except RecognitionException as re: localctx.exception = re @@ -6877,36 +6958,36 @@ def jsonata_template_value_object(self): self.enterRule(localctx, 110, self.RULE_jsonata_template_value_object) self._la = 0 # Token type try: - self.state = 724 + self.state = 730 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,44,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 711 + self.state = 717 self.match(ASLParser.LBRACE) - self.state = 712 + self.state = 718 self.match(ASLParser.RBRACE) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 713 + self.state = 719 self.match(ASLParser.LBRACE) - self.state = 714 + self.state = 720 self.jsonata_template_binding() - self.state = 719 + self.state = 725 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 715 + self.state = 721 self.match(ASLParser.COMMA) - self.state = 716 + self.state = 722 self.jsonata_template_binding() - self.state = 721 + self.state = 727 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 722 + self.state = 728 self.match(ASLParser.RBRACE) pass @@ -6964,11 +7045,11 @@ def jsonata_template_binding(self): self.enterRule(localctx, 112, self.RULE_jsonata_template_binding) try: self.enterOuterAlt(localctx, 1) - self.state = 726 + self.state = 732 self.keyword_or_string() - self.state = 727 + self.state = 733 self.match(ASLParser.COLON) - self.state = 728 + self.state = 734 self.jsonata_template_value() except RecognitionException as re: localctx.exception = re @@ -7023,22 +7104,22 @@ def jsonata_template_value(self): localctx = ASLParser.Jsonata_template_valueContext(self, self._ctx, self.state) self.enterRule(localctx, 114, self.RULE_jsonata_template_value) try: - self.state = 733 + self.state = 739 self._errHandler.sync(self) token = self._input.LA(1) if token in [5]: self.enterOuterAlt(localctx, 1) - self.state = 730 + self.state = 736 self.jsonata_template_value_object() pass elif token in [3]: self.enterOuterAlt(localctx, 2) - self.state = 731 + self.state = 737 self.jsonata_template_value_array() pass elif token in [7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 117, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 132, 133, 134, 135, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159]: self.enterOuterAlt(localctx, 3) - self.state = 732 + self.state = 738 self.jsonata_template_value_terminal() pass else: @@ -7105,36 +7186,36 @@ def jsonata_template_value_array(self): self.enterRule(localctx, 116, self.RULE_jsonata_template_value_array) self._la = 0 # Token type try: - self.state = 748 + self.state = 754 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,47,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 735 + self.state = 741 self.match(ASLParser.LBRACK) - self.state = 736 + self.state = 742 self.match(ASLParser.RBRACK) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 737 + self.state = 743 self.match(ASLParser.LBRACK) - self.state = 738 + self.state = 744 self.jsonata_template_value() - self.state = 743 + self.state = 749 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 739 + self.state = 745 self.match(ASLParser.COMMA) - self.state = 740 + self.state = 746 self.jsonata_template_value() - self.state = 745 + self.state = 751 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 746 + self.state = 752 self.match(ASLParser.RBRACK) pass @@ -7319,27 +7400,27 @@ def jsonata_template_value_terminal(self): self.enterRule(localctx, 118, self.RULE_jsonata_template_value_terminal) self._la = 0 # Token type try: - self.state = 756 + self.state = 762 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,48,self._ctx) if la_ == 1: localctx = ASLParser.Jsonata_template_value_terminal_floatContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 750 + self.state = 756 self.match(ASLParser.NUMBER) pass elif la_ == 2: localctx = ASLParser.Jsonata_template_value_terminal_intContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 751 + self.state = 757 self.match(ASLParser.INT) pass elif la_ == 3: localctx = ASLParser.Jsonata_template_value_terminal_boolContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 752 + self.state = 758 _la = self._input.LA(1) if not(_la==7 or _la==8): self._errHandler.recoverInline(self) @@ -7351,21 +7432,21 @@ def jsonata_template_value_terminal(self): elif la_ == 4: localctx = ASLParser.Jsonata_template_value_terminal_nullContext(self, localctx) self.enterOuterAlt(localctx, 4) - self.state = 753 + self.state = 759 self.match(ASLParser.NULL) pass elif la_ == 5: localctx = ASLParser.Jsonata_template_value_terminal_expressionContext(self, localctx) self.enterOuterAlt(localctx, 5) - self.state = 754 + self.state = 760 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 6: localctx = ASLParser.Jsonata_template_value_terminal_strContext(self, localctx) self.enterOuterAlt(localctx, 6) - self.state = 755 + self.state = 761 self.keyword_or_string() pass @@ -7422,11 +7503,11 @@ def result_selector_decl(self): self.enterRule(localctx, 120, self.RULE_result_selector_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 758 + self.state = 764 self.match(ASLParser.RESULTSELECTOR) - self.state = 759 + self.state = 765 self.match(ASLParser.COLON) - self.state = 760 + self.state = 766 self.payload_tmpl_decl() except RecognitionException as re: localctx.exception = re @@ -7495,7 +7576,7 @@ def state_type(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 762 + self.state = 768 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & 16711680) != 0)): self._errHandler.recoverInline(self) @@ -7570,27 +7651,27 @@ def choices_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 764 + self.state = 770 self.match(ASLParser.CHOICES) - self.state = 765 + self.state = 771 self.match(ASLParser.COLON) - self.state = 766 + self.state = 772 self.match(ASLParser.LBRACK) - self.state = 767 + self.state = 773 self.choice_rule() - self.state = 772 + self.state = 778 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 768 + self.state = 774 self.match(ASLParser.COMMA) - self.state = 769 + self.state = 775 self.choice_rule() - self.state = 774 + self.state = 780 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 775 + self.state = 781 self.match(ASLParser.RBRACK) except RecognitionException as re: localctx.exception = re @@ -7699,54 +7780,54 @@ def choice_rule(self): self.enterRule(localctx, 126, self.RULE_choice_rule) self._la = 0 # Token type try: - self.state = 798 + self.state = 804 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,52,self._ctx) if la_ == 1: localctx = ASLParser.Choice_rule_comparison_variableContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 777 + self.state = 783 self.match(ASLParser.LBRACE) - self.state = 778 + self.state = 784 self.comparison_variable_stmt() - self.state = 781 + self.state = 787 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 779 + self.state = 785 self.match(ASLParser.COMMA) - self.state = 780 + self.state = 786 self.comparison_variable_stmt() - self.state = 783 + self.state = 789 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==1): break - self.state = 785 + self.state = 791 self.match(ASLParser.RBRACE) pass elif la_ == 2: localctx = ASLParser.Choice_rule_comparison_compositeContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 787 + self.state = 793 self.match(ASLParser.LBRACE) - self.state = 788 + self.state = 794 self.comparison_composite_stmt() - self.state = 793 + self.state = 799 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 789 + self.state = 795 self.match(ASLParser.COMMA) - self.state = 790 + self.state = 796 self.comparison_composite_stmt() - self.state = 795 + self.state = 801 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 796 + self.state = 802 self.match(ASLParser.RBRACE) pass @@ -7812,32 +7893,32 @@ def comparison_variable_stmt(self): localctx = ASLParser.Comparison_variable_stmtContext(self, self._ctx, self.state) self.enterRule(localctx, 128, self.RULE_comparison_variable_stmt) try: - self.state = 805 + self.state = 811 self._errHandler.sync(self) token = self._input.LA(1) if token in [26]: self.enterOuterAlt(localctx, 1) - self.state = 800 + self.state = 806 self.variable_decl() pass elif token in [25, 30, 31, 32, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70]: self.enterOuterAlt(localctx, 2) - self.state = 801 + self.state = 807 self.comparison_func() pass elif token in [113]: self.enterOuterAlt(localctx, 3) - self.state = 802 + self.state = 808 self.next_decl() pass elif token in [132]: self.enterOuterAlt(localctx, 4) - self.state = 803 + self.state = 809 self.assign_decl() pass elif token in [10]: self.enterOuterAlt(localctx, 5) - self.state = 804 + self.state = 810 self.comment_decl() pass else: @@ -7900,27 +7981,27 @@ def comparison_composite_stmt(self): localctx = ASLParser.Comparison_composite_stmtContext(self, self._ctx, self.state) self.enterRule(localctx, 130, self.RULE_comparison_composite_stmt) try: - self.state = 811 + self.state = 817 self._errHandler.sync(self) token = self._input.LA(1) if token in [29, 38, 49]: self.enterOuterAlt(localctx, 1) - self.state = 807 + self.state = 813 self.comparison_composite() pass elif token in [113]: self.enterOuterAlt(localctx, 2) - self.state = 808 + self.state = 814 self.next_decl() pass elif token in [132]: self.enterOuterAlt(localctx, 3) - self.state = 809 + self.state = 815 self.assign_decl() pass elif token in [10]: self.enterOuterAlt(localctx, 4) - self.state = 810 + self.state = 816 self.comment_decl() pass else: @@ -7995,35 +8076,35 @@ def comparison_composite(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 813 + self.state = 819 self.choice_operator() - self.state = 814 + self.state = 820 self.match(ASLParser.COLON) - self.state = 827 + self.state = 833 self._errHandler.sync(self) token = self._input.LA(1) if token in [5]: - self.state = 815 + self.state = 821 self.choice_rule() pass elif token in [3]: - self.state = 816 + self.state = 822 self.match(ASLParser.LBRACK) - self.state = 817 + self.state = 823 self.choice_rule() - self.state = 822 + self.state = 828 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 818 + self.state = 824 self.match(ASLParser.COMMA) - self.state = 819 + self.state = 825 self.choice_rule() - self.state = 824 + self.state = 830 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 825 + self.state = 831 self.match(ASLParser.RBRACK) pass else: @@ -8146,39 +8227,39 @@ def variable_decl(self): localctx = ASLParser.Variable_declContext(self, self._ctx, self.state) self.enterRule(localctx, 134, self.RULE_variable_decl) try: - self.state = 838 + self.state = 844 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,57,self._ctx) if la_ == 1: localctx = ASLParser.Variable_decl_pathContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 829 + self.state = 835 self.match(ASLParser.VARIABLE) - self.state = 830 + self.state = 836 self.match(ASLParser.COLON) - self.state = 831 + self.state = 837 self.match(ASLParser.STRINGPATH) pass elif la_ == 2: localctx = ASLParser.Variable_decl_varContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 832 + self.state = 838 self.match(ASLParser.VARIABLE) - self.state = 833 + self.state = 839 self.match(ASLParser.COLON) - self.state = 834 + self.state = 840 self.variable_sample() pass elif la_ == 3: localctx = ASLParser.Variable_decl_path_context_objectContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 835 + self.state = 841 self.match(ASLParser.VARIABLE) - self.state = 836 + self.state = 842 self.match(ASLParser.COLON) - self.state = 837 + self.state = 843 self.match(ASLParser.STRINGPATHCONTEXTOBJ) pass @@ -8334,17 +8415,17 @@ def comparison_func(self): self.enterRule(localctx, 136, self.RULE_comparison_func) self._la = 0 # Token type try: - self.state = 854 + self.state = 860 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,58,self._ctx) if la_ == 1: localctx = ASLParser.Condition_litContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 840 + self.state = 846 self.match(ASLParser.CONDITION) - self.state = 841 + self.state = 847 self.match(ASLParser.COLON) - self.state = 842 + self.state = 848 _la = self._input.LA(1) if not(_la==7 or _la==8): self._errHandler.recoverInline(self) @@ -8356,33 +8437,33 @@ def comparison_func(self): elif la_ == 2: localctx = ASLParser.Condition_exprContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 843 + self.state = 849 self.match(ASLParser.CONDITION) - self.state = 844 + self.state = 850 self.match(ASLParser.COLON) - self.state = 845 + self.state = 851 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 3: localctx = ASLParser.Comparison_func_varContext(self, localctx) self.enterOuterAlt(localctx, 3) - self.state = 846 + self.state = 852 self.comparison_op() - self.state = 847 + self.state = 853 self.match(ASLParser.COLON) - self.state = 848 + self.state = 854 self.variable_sample() pass elif la_ == 4: localctx = ASLParser.Comparison_func_valueContext(self, localctx) self.enterOuterAlt(localctx, 4) - self.state = 850 + self.state = 856 self.comparison_op() - self.state = 851 + self.state = 857 self.match(ASLParser.COLON) - self.state = 852 + self.state = 858 self.json_value_decl() pass @@ -8455,27 +8536,27 @@ def branches_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 856 + self.state = 862 self.match(ASLParser.BRANCHES) - self.state = 857 + self.state = 863 self.match(ASLParser.COLON) - self.state = 858 + self.state = 864 self.match(ASLParser.LBRACK) - self.state = 859 + self.state = 865 self.program_decl() - self.state = 864 + self.state = 870 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 860 + self.state = 866 self.match(ASLParser.COMMA) - self.state = 861 + self.state = 867 self.program_decl() - self.state = 866 + self.state = 872 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 867 + self.state = 873 self.match(ASLParser.RBRACK) except RecognitionException as re: localctx.exception = re @@ -8545,27 +8626,27 @@ def item_processor_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 869 + self.state = 875 self.match(ASLParser.ITEMPROCESSOR) - self.state = 870 + self.state = 876 self.match(ASLParser.COLON) - self.state = 871 + self.state = 877 self.match(ASLParser.LBRACE) - self.state = 872 + self.state = 878 self.item_processor_item() - self.state = 877 + self.state = 883 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 873 + self.state = 879 self.match(ASLParser.COMMA) - self.state = 874 + self.state = 880 self.item_processor_item() - self.state = 879 + self.state = 885 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 880 + self.state = 886 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -8624,27 +8705,27 @@ def item_processor_item(self): localctx = ASLParser.Item_processor_itemContext(self, self._ctx, self.state) self.enterRule(localctx, 142, self.RULE_item_processor_item) try: - self.state = 886 + self.state = 892 self._errHandler.sync(self) token = self._input.LA(1) if token in [79]: self.enterOuterAlt(localctx, 1) - self.state = 882 + self.state = 888 self.processor_config_decl() pass elif token in [12]: self.enterOuterAlt(localctx, 2) - self.state = 883 + self.state = 889 self.startat_decl() pass elif token in [11]: self.enterOuterAlt(localctx, 3) - self.state = 884 + self.state = 890 self.states_decl() pass elif token in [10]: self.enterOuterAlt(localctx, 4) - self.state = 885 + self.state = 891 self.comment_decl() pass else: @@ -8718,27 +8799,27 @@ def processor_config_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 888 + self.state = 894 self.match(ASLParser.PROCESSORCONFIG) - self.state = 889 + self.state = 895 self.match(ASLParser.COLON) - self.state = 890 + self.state = 896 self.match(ASLParser.LBRACE) - self.state = 891 + self.state = 897 self.processor_config_field() - self.state = 896 + self.state = 902 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 892 + self.state = 898 self.match(ASLParser.COMMA) - self.state = 893 + self.state = 899 self.processor_config_field() - self.state = 898 + self.state = 904 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 899 + self.state = 905 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -8789,17 +8870,17 @@ def processor_config_field(self): localctx = ASLParser.Processor_config_fieldContext(self, self._ctx, self.state) self.enterRule(localctx, 146, self.RULE_processor_config_field) try: - self.state = 903 + self.state = 909 self._errHandler.sync(self) token = self._input.LA(1) if token in [80]: self.enterOuterAlt(localctx, 1) - self.state = 901 + self.state = 907 self.mode_decl() pass elif token in [83]: self.enterOuterAlt(localctx, 2) - self.state = 902 + self.state = 908 self.execution_decl() pass else: @@ -8857,11 +8938,11 @@ def mode_decl(self): self.enterRule(localctx, 148, self.RULE_mode_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 905 + self.state = 911 self.match(ASLParser.MODE) - self.state = 906 + self.state = 912 self.match(ASLParser.COLON) - self.state = 907 + self.state = 913 self.mode_type() except RecognitionException as re: localctx.exception = re @@ -8912,7 +8993,7 @@ def mode_type(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 909 + self.state = 915 _la = self._input.LA(1) if not(_la==81 or _la==82): self._errHandler.recoverInline(self) @@ -8971,11 +9052,11 @@ def execution_decl(self): self.enterRule(localctx, 152, self.RULE_execution_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 911 + self.state = 917 self.match(ASLParser.EXECUTIONTYPE) - self.state = 912 + self.state = 918 self.match(ASLParser.COLON) - self.state = 913 + self.state = 919 self.execution_type() except RecognitionException as re: localctx.exception = re @@ -9022,7 +9103,7 @@ def execution_type(self): self.enterRule(localctx, 154, self.RULE_execution_type) try: self.enterOuterAlt(localctx, 1) - self.state = 915 + self.state = 921 self.match(ASLParser.STANDARD) except RecognitionException as re: localctx.exception = re @@ -9092,27 +9173,27 @@ def iterator_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 917 + self.state = 923 self.match(ASLParser.ITERATOR) - self.state = 918 + self.state = 924 self.match(ASLParser.COLON) - self.state = 919 + self.state = 925 self.match(ASLParser.LBRACE) - self.state = 920 + self.state = 926 self.iterator_decl_item() - self.state = 925 + self.state = 931 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 921 + self.state = 927 self.match(ASLParser.COMMA) - self.state = 922 + self.state = 928 self.iterator_decl_item() - self.state = 927 + self.state = 933 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 928 + self.state = 934 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -9171,27 +9252,27 @@ def iterator_decl_item(self): localctx = ASLParser.Iterator_decl_itemContext(self, self._ctx, self.state) self.enterRule(localctx, 158, self.RULE_iterator_decl_item) try: - self.state = 934 + self.state = 940 self._errHandler.sync(self) token = self._input.LA(1) if token in [12]: self.enterOuterAlt(localctx, 1) - self.state = 930 + self.state = 936 self.startat_decl() pass elif token in [11]: self.enterOuterAlt(localctx, 2) - self.state = 931 + self.state = 937 self.states_decl() pass elif token in [10]: self.enterOuterAlt(localctx, 3) - self.state = 932 + self.state = 938 self.comment_decl() pass elif token in [79]: self.enterOuterAlt(localctx, 4) - self.state = 933 + self.state = 939 self.processor_config_decl() pass else: @@ -9249,11 +9330,11 @@ def item_selector_decl(self): self.enterRule(localctx, 160, self.RULE_item_selector_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 936 + self.state = 942 self.match(ASLParser.ITEMSELECTOR) - self.state = 937 + self.state = 943 self.match(ASLParser.COLON) - self.state = 938 + self.state = 944 self.payload_tmpl_decl() except RecognitionException as re: localctx.exception = re @@ -9323,27 +9404,27 @@ def item_reader_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 940 + self.state = 946 self.match(ASLParser.ITEMREADER) - self.state = 941 + self.state = 947 self.match(ASLParser.COLON) - self.state = 942 + self.state = 948 self.match(ASLParser.LBRACE) - self.state = 943 + self.state = 949 self.items_reader_field() - self.state = 948 + self.state = 954 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 944 + self.state = 950 self.match(ASLParser.COMMA) - self.state = 945 + self.state = 951 self.items_reader_field() - self.state = 950 + self.state = 956 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 951 + self.state = 957 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -9402,27 +9483,27 @@ def items_reader_field(self): localctx = ASLParser.Items_reader_fieldContext(self, self._ctx, self.state) self.enterRule(localctx, 164, self.RULE_items_reader_field) try: - self.state = 957 + self.state = 963 self._errHandler.sync(self) token = self._input.LA(1) if token in [90]: self.enterOuterAlt(localctx, 1) - self.state = 953 + self.state = 959 self.resource_decl() pass elif token in [101]: self.enterOuterAlt(localctx, 2) - self.state = 954 + self.state = 960 self.reader_config_decl() pass elif token in [97]: self.enterOuterAlt(localctx, 3) - self.state = 955 + self.state = 961 self.parameters_decl() pass elif token in [134]: self.enterOuterAlt(localctx, 4) - self.state = 956 + self.state = 962 self.arguments_decl() pass else: @@ -9496,27 +9577,27 @@ def reader_config_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 959 + self.state = 965 self.match(ASLParser.READERCONFIG) - self.state = 960 + self.state = 966 self.match(ASLParser.COLON) - self.state = 961 + self.state = 967 self.match(ASLParser.LBRACE) - self.state = 962 + self.state = 968 self.reader_config_field() - self.state = 967 + self.state = 973 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 963 + self.state = 969 self.match(ASLParser.COMMA) - self.state = 964 + self.state = 970 self.reader_config_field() - self.state = 969 + self.state = 975 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 970 + self.state = 976 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -9579,32 +9660,32 @@ def reader_config_field(self): localctx = ASLParser.Reader_config_fieldContext(self, self._ctx, self.state) self.enterRule(localctx, 168, self.RULE_reader_config_field) try: - self.state = 977 + self.state = 983 self._errHandler.sync(self) token = self._input.LA(1) if token in [102]: self.enterOuterAlt(localctx, 1) - self.state = 972 + self.state = 978 self.input_type_decl() pass elif token in [103]: self.enterOuterAlt(localctx, 2) - self.state = 973 + self.state = 979 self.csv_header_location_decl() pass elif token in [104]: self.enterOuterAlt(localctx, 3) - self.state = 974 + self.state = 980 self.csv_headers_decl() pass elif token in [105]: self.enterOuterAlt(localctx, 4) - self.state = 975 + self.state = 981 self.max_items_decl() pass elif token in [106]: self.enterOuterAlt(localctx, 5) - self.state = 976 + self.state = 982 self.max_items_path_decl() pass else: @@ -9662,11 +9743,11 @@ def input_type_decl(self): self.enterRule(localctx, 170, self.RULE_input_type_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 979 + self.state = 985 self.match(ASLParser.INPUTTYPE) - self.state = 980 + self.state = 986 self.match(ASLParser.COLON) - self.state = 981 + self.state = 987 self.keyword_or_string() except RecognitionException as re: localctx.exception = re @@ -9720,11 +9801,11 @@ def csv_header_location_decl(self): self.enterRule(localctx, 172, self.RULE_csv_header_location_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 983 + self.state = 989 self.match(ASLParser.CSVHEADERLOCATION) - self.state = 984 + self.state = 990 self.match(ASLParser.COLON) - self.state = 985 + self.state = 991 self.keyword_or_string() except RecognitionException as re: localctx.exception = re @@ -9794,27 +9875,27 @@ def csv_headers_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 987 + self.state = 993 self.match(ASLParser.CSVHEADERS) - self.state = 988 + self.state = 994 self.match(ASLParser.COLON) - self.state = 989 + self.state = 995 self.match(ASLParser.LBRACK) - self.state = 990 + self.state = 996 self.keyword_or_string() - self.state = 995 + self.state = 1001 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 991 + self.state = 997 self.match(ASLParser.COMMA) - self.state = 992 + self.state = 998 self.keyword_or_string() - self.state = 997 + self.state = 1003 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 998 + self.state = 1004 self.match(ASLParser.RBRACK) except RecognitionException as re: localctx.exception = re @@ -9904,28 +9985,28 @@ def max_items_decl(self): localctx = ASLParser.Max_items_declContext(self, self._ctx, self.state) self.enterRule(localctx, 176, self.RULE_max_items_decl) try: - self.state = 1006 + self.state = 1012 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,71,self._ctx) if la_ == 1: localctx = ASLParser.Max_items_jsonataContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 1000 + self.state = 1006 self.match(ASLParser.MAXITEMS) - self.state = 1001 + self.state = 1007 self.match(ASLParser.COLON) - self.state = 1002 + self.state = 1008 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 2: localctx = ASLParser.Max_items_intContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 1003 + self.state = 1009 self.match(ASLParser.MAXITEMS) - self.state = 1004 + self.state = 1010 self.match(ASLParser.COLON) - self.state = 1005 + self.state = 1011 self.match(ASLParser.INT) pass @@ -10019,28 +10100,28 @@ def max_items_path_decl(self): localctx = ASLParser.Max_items_path_declContext(self, self._ctx, self.state) self.enterRule(localctx, 178, self.RULE_max_items_path_decl) try: - self.state = 1014 + self.state = 1020 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,72,self._ctx) if la_ == 1: localctx = ASLParser.Max_items_path_varContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 1008 + self.state = 1014 self.match(ASLParser.MAXITEMSPATH) - self.state = 1009 + self.state = 1015 self.match(ASLParser.COLON) - self.state = 1010 + self.state = 1016 self.variable_sample() pass elif la_ == 2: localctx = ASLParser.Max_items_pathContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 1011 + self.state = 1017 self.match(ASLParser.MAXITEMSPATH) - self.state = 1012 + self.state = 1018 self.match(ASLParser.COLON) - self.state = 1013 + self.state = 1019 self.match(ASLParser.STRINGPATH) pass @@ -10133,28 +10214,28 @@ def tolerated_failure_count_decl(self): localctx = ASLParser.Tolerated_failure_count_declContext(self, self._ctx, self.state) self.enterRule(localctx, 180, self.RULE_tolerated_failure_count_decl) try: - self.state = 1022 + self.state = 1028 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,73,self._ctx) if la_ == 1: localctx = ASLParser.Tolerated_failure_count_jsonataContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 1016 + self.state = 1022 self.match(ASLParser.TOLERATEDFAILURECOUNT) - self.state = 1017 + self.state = 1023 self.match(ASLParser.COLON) - self.state = 1018 + self.state = 1024 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 2: localctx = ASLParser.Tolerated_failure_count_intContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 1019 + self.state = 1025 self.match(ASLParser.TOLERATEDFAILURECOUNT) - self.state = 1020 + self.state = 1026 self.match(ASLParser.COLON) - self.state = 1021 + self.state = 1027 self.match(ASLParser.INT) pass @@ -10248,28 +10329,28 @@ def tolerated_failure_count_path_decl(self): localctx = ASLParser.Tolerated_failure_count_path_declContext(self, self._ctx, self.state) self.enterRule(localctx, 182, self.RULE_tolerated_failure_count_path_decl) try: - self.state = 1030 + self.state = 1036 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,74,self._ctx) if la_ == 1: localctx = ASLParser.Tolerated_failure_count_path_varContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 1024 + self.state = 1030 self.match(ASLParser.TOLERATEDFAILURECOUNTPATH) - self.state = 1025 + self.state = 1031 self.match(ASLParser.COLON) - self.state = 1026 + self.state = 1032 self.variable_sample() pass elif la_ == 2: localctx = ASLParser.Tolerated_failure_count_pathContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 1027 + self.state = 1033 self.match(ASLParser.TOLERATEDFAILURECOUNTPATH) - self.state = 1028 + self.state = 1034 self.match(ASLParser.COLON) - self.state = 1029 + self.state = 1035 self.match(ASLParser.STRINGPATH) pass @@ -10362,28 +10443,28 @@ def tolerated_failure_percentage_decl(self): localctx = ASLParser.Tolerated_failure_percentage_declContext(self, self._ctx, self.state) self.enterRule(localctx, 184, self.RULE_tolerated_failure_percentage_decl) try: - self.state = 1038 + self.state = 1044 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,75,self._ctx) if la_ == 1: localctx = ASLParser.Tolerated_failure_percentage_jsonataContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 1032 + self.state = 1038 self.match(ASLParser.TOLERATEDFAILUREPERCENTAGE) - self.state = 1033 + self.state = 1039 self.match(ASLParser.COLON) - self.state = 1034 + self.state = 1040 self.match(ASLParser.STRINGJSONATA) pass elif la_ == 2: localctx = ASLParser.Tolerated_failure_percentage_numberContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 1035 + self.state = 1041 self.match(ASLParser.TOLERATEDFAILUREPERCENTAGE) - self.state = 1036 + self.state = 1042 self.match(ASLParser.COLON) - self.state = 1037 + self.state = 1043 self.match(ASLParser.NUMBER) pass @@ -10477,28 +10558,28 @@ def tolerated_failure_percentage_path_decl(self): localctx = ASLParser.Tolerated_failure_percentage_path_declContext(self, self._ctx, self.state) self.enterRule(localctx, 186, self.RULE_tolerated_failure_percentage_path_decl) try: - self.state = 1046 + self.state = 1052 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,76,self._ctx) if la_ == 1: localctx = ASLParser.Tolerated_failure_percentage_path_varContext(self, localctx) self.enterOuterAlt(localctx, 1) - self.state = 1040 + self.state = 1046 self.match(ASLParser.TOLERATEDFAILUREPERCENTAGEPATH) - self.state = 1041 + self.state = 1047 self.match(ASLParser.COLON) - self.state = 1042 + self.state = 1048 self.variable_sample() pass elif la_ == 2: localctx = ASLParser.Tolerated_failure_percentage_pathContext(self, localctx) self.enterOuterAlt(localctx, 2) - self.state = 1043 + self.state = 1049 self.match(ASLParser.TOLERATEDFAILUREPERCENTAGEPATH) - self.state = 1044 + self.state = 1050 self.match(ASLParser.COLON) - self.state = 1045 + self.state = 1051 self.match(ASLParser.STRINGPATH) pass @@ -10555,11 +10636,11 @@ def label_decl(self): self.enterRule(localctx, 188, self.RULE_label_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 1048 + self.state = 1054 self.match(ASLParser.LABEL) - self.state = 1049 + self.state = 1055 self.match(ASLParser.COLON) - self.state = 1050 + self.state = 1056 self.keyword_or_string() except RecognitionException as re: localctx.exception = re @@ -10629,27 +10710,27 @@ def result_writer_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1052 + self.state = 1058 self.match(ASLParser.RESULTWRITER) - self.state = 1053 + self.state = 1059 self.match(ASLParser.COLON) - self.state = 1054 + self.state = 1060 self.match(ASLParser.LBRACE) - self.state = 1055 + self.state = 1061 self.result_writer_field() - self.state = 1060 + self.state = 1066 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1056 + self.state = 1062 self.match(ASLParser.COMMA) - self.state = 1057 + self.state = 1063 self.result_writer_field() - self.state = 1062 + self.state = 1068 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1063 + self.state = 1069 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -10700,17 +10781,17 @@ def result_writer_field(self): localctx = ASLParser.Result_writer_fieldContext(self, self._ctx, self.state) self.enterRule(localctx, 192, self.RULE_result_writer_field) try: - self.state = 1067 + self.state = 1073 self._errHandler.sync(self) token = self._input.LA(1) if token in [90]: self.enterOuterAlt(localctx, 1) - self.state = 1065 + self.state = 1071 self.resource_decl() pass elif token in [97]: self.enterOuterAlt(localctx, 2) - self.state = 1066 + self.state = 1072 self.parameters_decl() pass else: @@ -10784,33 +10865,33 @@ def retry_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1069 + self.state = 1075 self.match(ASLParser.RETRY) - self.state = 1070 + self.state = 1076 self.match(ASLParser.COLON) - self.state = 1071 + self.state = 1077 self.match(ASLParser.LBRACK) - self.state = 1080 + self.state = 1086 self._errHandler.sync(self) _la = self._input.LA(1) if _la==5: - self.state = 1072 + self.state = 1078 self.retrier_decl() - self.state = 1077 + self.state = 1083 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1073 + self.state = 1079 self.match(ASLParser.COMMA) - self.state = 1074 + self.state = 1080 self.retrier_decl() - self.state = 1079 + self.state = 1085 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1082 + self.state = 1088 self.match(ASLParser.RBRACK) except RecognitionException as re: localctx.exception = re @@ -10874,23 +10955,23 @@ def retrier_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1084 + self.state = 1090 self.match(ASLParser.LBRACE) - self.state = 1085 + self.state = 1091 self.retrier_stmt() - self.state = 1090 + self.state = 1096 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1086 + self.state = 1092 self.match(ASLParser.COMMA) - self.state = 1087 + self.state = 1093 self.retrier_stmt() - self.state = 1092 + self.state = 1098 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1093 + self.state = 1099 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -10961,42 +11042,42 @@ def retrier_stmt(self): localctx = ASLParser.Retrier_stmtContext(self, self._ctx, self.state) self.enterRule(localctx, 198, self.RULE_retrier_stmt) try: - self.state = 1102 + self.state = 1108 self._errHandler.sync(self) token = self._input.LA(1) if token in [120]: self.enterOuterAlt(localctx, 1) - self.state = 1095 + self.state = 1101 self.error_equals_decl() pass elif token in [121]: self.enterOuterAlt(localctx, 2) - self.state = 1096 + self.state = 1102 self.interval_seconds_decl() pass elif token in [122]: self.enterOuterAlt(localctx, 3) - self.state = 1097 + self.state = 1103 self.max_attempts_decl() pass elif token in [123]: self.enterOuterAlt(localctx, 4) - self.state = 1098 + self.state = 1104 self.backoff_rate_decl() pass elif token in [124]: self.enterOuterAlt(localctx, 5) - self.state = 1099 + self.state = 1105 self.max_delay_seconds_decl() pass elif token in [125]: self.enterOuterAlt(localctx, 6) - self.state = 1100 + self.state = 1106 self.jitter_strategy_decl() pass elif token in [10]: self.enterOuterAlt(localctx, 7) - self.state = 1101 + self.state = 1107 self.comment_decl() pass else: @@ -11070,27 +11151,27 @@ def error_equals_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1104 + self.state = 1110 self.match(ASLParser.ERROREQUALS) - self.state = 1105 + self.state = 1111 self.match(ASLParser.COLON) - self.state = 1106 + self.state = 1112 self.match(ASLParser.LBRACK) - self.state = 1107 + self.state = 1113 self.error_name() - self.state = 1112 + self.state = 1118 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1108 + self.state = 1114 self.match(ASLParser.COMMA) - self.state = 1109 + self.state = 1115 self.error_name() - self.state = 1114 + self.state = 1120 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1115 + self.state = 1121 self.match(ASLParser.RBRACK) except RecognitionException as re: localctx.exception = re @@ -11143,11 +11224,11 @@ def interval_seconds_decl(self): self.enterRule(localctx, 202, self.RULE_interval_seconds_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 1117 + self.state = 1123 self.match(ASLParser.INTERVALSECONDS) - self.state = 1118 + self.state = 1124 self.match(ASLParser.COLON) - self.state = 1119 + self.state = 1125 self.match(ASLParser.INT) except RecognitionException as re: localctx.exception = re @@ -11200,11 +11281,11 @@ def max_attempts_decl(self): self.enterRule(localctx, 204, self.RULE_max_attempts_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 1121 + self.state = 1127 self.match(ASLParser.MAXATTEMPTS) - self.state = 1122 + self.state = 1128 self.match(ASLParser.COLON) - self.state = 1123 + self.state = 1129 self.match(ASLParser.INT) except RecognitionException as re: localctx.exception = re @@ -11261,11 +11342,11 @@ def backoff_rate_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1125 + self.state = 1131 self.match(ASLParser.BACKOFFRATE) - self.state = 1126 + self.state = 1132 self.match(ASLParser.COLON) - self.state = 1127 + self.state = 1133 _la = self._input.LA(1) if not(_la==158 or _la==159): self._errHandler.recoverInline(self) @@ -11323,11 +11404,11 @@ def max_delay_seconds_decl(self): self.enterRule(localctx, 208, self.RULE_max_delay_seconds_decl) try: self.enterOuterAlt(localctx, 1) - self.state = 1129 + self.state = 1135 self.match(ASLParser.MAXDELAYSECONDS) - self.state = 1130 + self.state = 1136 self.match(ASLParser.COLON) - self.state = 1131 + self.state = 1137 self.match(ASLParser.INT) except RecognitionException as re: localctx.exception = re @@ -11384,11 +11465,11 @@ def jitter_strategy_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1133 + self.state = 1139 self.match(ASLParser.JITTERSTRATEGY) - self.state = 1134 + self.state = 1140 self.match(ASLParser.COLON) - self.state = 1135 + self.state = 1141 _la = self._input.LA(1) if not(_la==126 or _la==127): self._errHandler.recoverInline(self) @@ -11463,33 +11544,33 @@ def catch_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1137 + self.state = 1143 self.match(ASLParser.CATCH) - self.state = 1138 + self.state = 1144 self.match(ASLParser.COLON) - self.state = 1139 + self.state = 1145 self.match(ASLParser.LBRACK) - self.state = 1148 + self.state = 1154 self._errHandler.sync(self) _la = self._input.LA(1) if _la==5: - self.state = 1140 + self.state = 1146 self.catcher_decl() - self.state = 1145 + self.state = 1151 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1141 + self.state = 1147 self.match(ASLParser.COMMA) - self.state = 1142 + self.state = 1148 self.catcher_decl() - self.state = 1147 + self.state = 1153 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1150 + self.state = 1156 self.match(ASLParser.RBRACK) except RecognitionException as re: localctx.exception = re @@ -11553,23 +11634,23 @@ def catcher_decl(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1152 + self.state = 1158 self.match(ASLParser.LBRACE) - self.state = 1153 + self.state = 1159 self.catcher_stmt() - self.state = 1158 + self.state = 1164 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1154 + self.state = 1160 self.match(ASLParser.COMMA) - self.state = 1155 + self.state = 1161 self.catcher_stmt() - self.state = 1160 + self.state = 1166 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1161 + self.state = 1167 self.match(ASLParser.RBRACE) except RecognitionException as re: localctx.exception = re @@ -11636,37 +11717,37 @@ def catcher_stmt(self): localctx = ASLParser.Catcher_stmtContext(self, self._ctx, self.state) self.enterRule(localctx, 216, self.RULE_catcher_stmt) try: - self.state = 1169 + self.state = 1175 self._errHandler.sync(self) token = self._input.LA(1) if token in [120]: self.enterOuterAlt(localctx, 1) - self.state = 1163 + self.state = 1169 self.error_equals_decl() pass elif token in [95]: self.enterOuterAlt(localctx, 2) - self.state = 1164 + self.state = 1170 self.result_path_decl() pass elif token in [113]: self.enterOuterAlt(localctx, 3) - self.state = 1165 + self.state = 1171 self.next_decl() pass elif token in [132]: self.enterOuterAlt(localctx, 4) - self.state = 1166 + self.state = 1172 self.assign_decl() pass elif token in [133]: self.enterOuterAlt(localctx, 5) - self.state = 1167 + self.state = 1173 self.output_decl() pass elif token in [10]: self.enterOuterAlt(localctx, 6) - self.state = 1168 + self.state = 1174 self.comment_decl() pass else: @@ -11832,7 +11913,7 @@ def comparison_op(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1171 + self.state = 1177 _la = self._input.LA(1) if not(((((_la - 30)) & ~0x3f) == 0 and ((1 << (_la - 30)) & 2199022731007) != 0)): self._errHandler.recoverInline(self) @@ -11891,7 +11972,7 @@ def choice_operator(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1173 + self.state = 1179 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & 563225368199168) != 0)): self._errHandler.recoverInline(self) @@ -11989,7 +12070,7 @@ def states_error_name(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1175 + self.state = 1181 _la = self._input.LA(1) if not(((((_la - 135)) & ~0x3f) == 0 and ((1 << (_la - 135)) & 65535) != 0)): self._errHandler.recoverInline(self) @@ -12045,18 +12126,18 @@ def error_name(self): localctx = ASLParser.Error_nameContext(self, self._ctx, self.state) self.enterRule(localctx, 224, self.RULE_error_name) try: - self.state = 1179 + self.state = 1185 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,88,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 1177 + self.state = 1183 self.states_error_name() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 1178 + self.state = 1184 self.keyword_or_string() pass @@ -12122,36 +12203,36 @@ def json_obj_decl(self): self.enterRule(localctx, 226, self.RULE_json_obj_decl) self._la = 0 # Token type try: - self.state = 1194 + self.state = 1200 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,90,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 1181 + self.state = 1187 self.match(ASLParser.LBRACE) - self.state = 1182 + self.state = 1188 self.json_binding() - self.state = 1187 + self.state = 1193 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1183 + self.state = 1189 self.match(ASLParser.COMMA) - self.state = 1184 + self.state = 1190 self.json_binding() - self.state = 1189 + self.state = 1195 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1190 + self.state = 1196 self.match(ASLParser.RBRACE) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 1192 + self.state = 1198 self.match(ASLParser.LBRACE) - self.state = 1193 + self.state = 1199 self.match(ASLParser.RBRACE) pass @@ -12209,11 +12290,11 @@ def json_binding(self): self.enterRule(localctx, 228, self.RULE_json_binding) try: self.enterOuterAlt(localctx, 1) - self.state = 1196 + self.state = 1202 self.keyword_or_string() - self.state = 1197 + self.state = 1203 self.match(ASLParser.COLON) - self.state = 1198 + self.state = 1204 self.json_value_decl() except RecognitionException as re: localctx.exception = re @@ -12276,36 +12357,36 @@ def json_arr_decl(self): self.enterRule(localctx, 230, self.RULE_json_arr_decl) self._la = 0 # Token type try: - self.state = 1213 + self.state = 1219 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,92,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 1200 + self.state = 1206 self.match(ASLParser.LBRACK) - self.state = 1201 + self.state = 1207 self.json_value_decl() - self.state = 1206 + self.state = 1212 self._errHandler.sync(self) _la = self._input.LA(1) while _la==1: - self.state = 1202 + self.state = 1208 self.match(ASLParser.COMMA) - self.state = 1203 + self.state = 1209 self.json_value_decl() - self.state = 1208 + self.state = 1214 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 1209 + self.state = 1215 self.match(ASLParser.RBRACK) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 1211 + self.state = 1217 self.match(ASLParser.LBRACK) - self.state = 1212 + self.state = 1218 self.match(ASLParser.RBRACK) pass @@ -12382,60 +12463,60 @@ def json_value_decl(self): localctx = ASLParser.Json_value_declContext(self, self._ctx, self.state) self.enterRule(localctx, 232, self.RULE_json_value_decl) try: - self.state = 1224 + self.state = 1230 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,93,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 1215 + self.state = 1221 self.match(ASLParser.NUMBER) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 1216 + self.state = 1222 self.match(ASLParser.INT) pass elif la_ == 3: self.enterOuterAlt(localctx, 3) - self.state = 1217 + self.state = 1223 self.match(ASLParser.TRUE) pass elif la_ == 4: self.enterOuterAlt(localctx, 4) - self.state = 1218 + self.state = 1224 self.match(ASLParser.FALSE) pass elif la_ == 5: self.enterOuterAlt(localctx, 5) - self.state = 1219 + self.state = 1225 self.match(ASLParser.NULL) pass elif la_ == 6: self.enterOuterAlt(localctx, 6) - self.state = 1220 + self.state = 1226 self.json_binding() pass elif la_ == 7: self.enterOuterAlt(localctx, 7) - self.state = 1221 + self.state = 1227 self.json_arr_decl() pass elif la_ == 8: self.enterOuterAlt(localctx, 8) - self.state = 1222 + self.state = 1228 self.json_obj_decl() pass elif la_ == 9: self.enterOuterAlt(localctx, 9) - self.state = 1223 + self.state = 1229 self.keyword_or_string() pass @@ -12909,7 +12990,7 @@ def keyword_or_string(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 1226 + self.state = 1232 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & -17408) != 0) or ((((_la - 64)) & ~0x3f) == 0 and ((1 << (_la - 64)) & -22517998136852481) != 0) or ((((_la - 128)) & ~0x3f) == 0 and ((1 << (_la - 128)) & 1073741555) != 0)): self._errHandler.recoverInline(self) diff --git a/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParserListener.py b/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParserListener.py index d876b115ce6f2..75043f5729912 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParserListener.py +++ b/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParserListener.py @@ -269,6 +269,15 @@ def exitError_path_decl_path(self, ctx:ASLParser.Error_path_decl_pathContext): pass + # Enter a parse tree produced by ASLParser#error_path_decl_context. + def enterError_path_decl_context(self, ctx:ASLParser.Error_path_decl_contextContext): + pass + + # Exit a parse tree produced by ASLParser#error_path_decl_context. + def exitError_path_decl_context(self, ctx:ASLParser.Error_path_decl_contextContext): + pass + + # Enter a parse tree produced by ASLParser#error_path_decl_intrinsic. def enterError_path_decl_intrinsic(self, ctx:ASLParser.Error_path_decl_intrinsicContext): pass @@ -314,6 +323,15 @@ def exitCause_path_decl_path(self, ctx:ASLParser.Cause_path_decl_pathContext): pass + # Enter a parse tree produced by ASLParser#cause_path_decl_context. + def enterCause_path_decl_context(self, ctx:ASLParser.Cause_path_decl_contextContext): + pass + + # Exit a parse tree produced by ASLParser#cause_path_decl_context. + def exitCause_path_decl_context(self, ctx:ASLParser.Cause_path_decl_contextContext): + pass + + # Enter a parse tree produced by ASLParser#cause_path_decl_intrinsic. def enterCause_path_decl_intrinsic(self, ctx:ASLParser.Cause_path_decl_intrinsicContext): pass diff --git a/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParserVisitor.py b/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParserVisitor.py index ba8c9d5fdbba6..a776510996f69 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParserVisitor.py +++ b/localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParserVisitor.py @@ -154,6 +154,11 @@ def visitError_path_decl_path(self, ctx:ASLParser.Error_path_decl_pathContext): return self.visitChildren(ctx) + # Visit a parse tree produced by ASLParser#error_path_decl_context. + def visitError_path_decl_context(self, ctx:ASLParser.Error_path_decl_contextContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#error_path_decl_intrinsic. def visitError_path_decl_intrinsic(self, ctx:ASLParser.Error_path_decl_intrinsicContext): return self.visitChildren(ctx) @@ -179,6 +184,11 @@ def visitCause_path_decl_path(self, ctx:ASLParser.Cause_path_decl_pathContext): return self.visitChildren(ctx) + # Visit a parse tree produced by ASLParser#cause_path_decl_context. + def visitCause_path_decl_context(self, ctx:ASLParser.Cause_path_decl_contextContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#cause_path_decl_intrinsic. def visitCause_path_decl_intrinsic(self, ctx:ASLParser.Cause_path_decl_intrinsicContext): return self.visitChildren(ctx) diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_fail/cause_decl.py b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_fail/cause_decl.py index 5b4be5aa9b692..846e8d6bf2857 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_fail/cause_decl.py +++ b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_fail/cause_decl.py @@ -1,4 +1,5 @@ import abc +import copy from typing import Final from localstack.services.stepfunctions.asl.component.common.jsonata.jsonata_template_value_terminal import ( @@ -72,6 +73,12 @@ def _eval_body(self, env: Environment) -> None: env.stack.append(cause) +class CausePathContextObject(CauseConst): + def _eval_body(self, env: Environment) -> None: + value = extract_json(self.value, env.states.context_object.context_object_data) + env.stack.append(copy.deepcopy(value)) + + class CausePathIntrinsicFunction(CauseConst): function: Final[Function] diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_fail/error_decl.py b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_fail/error_decl.py index e576d429a94ee..184e4f7791b11 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_fail/error_decl.py +++ b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_fail/error_decl.py @@ -1,4 +1,5 @@ import abc +import copy from typing import Final from localstack.services.stepfunctions.asl.component.common.jsonata.jsonata_template_value_terminal import ( @@ -72,6 +73,12 @@ def _eval_body(self, env: Environment) -> None: env.stack.append(cause) +class ErrorPathContextObject(ErrorConst): + def _eval_body(self, env: Environment) -> None: + value = extract_json(self.value, env.states.context_object.context_object_data) + env.stack.append(copy.deepcopy(value)) + + class ErrorPathIntrinsicFunction(ErrorConst): function: Final[Function] diff --git a/localstack-core/localstack/services/stepfunctions/asl/parse/preprocessor.py b/localstack-core/localstack/services/stepfunctions/asl/parse/preprocessor.py index 73b9ffe93cf91..a92e78ebf9cf9 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/parse/preprocessor.py +++ b/localstack-core/localstack/services/stepfunctions/asl/parse/preprocessor.py @@ -309,6 +309,7 @@ CauseConst, CauseDecl, CauseJSONata, + CausePathContextObject, CausePathIntrinsicFunction, CausePathJsonPath, CauseVar, @@ -317,6 +318,7 @@ ErrorConst, ErrorDecl, ErrorJSONata, + ErrorPathContextObject, ErrorPathIntrinsicFunction, ErrorPathJsonPath, ErrorVar, @@ -874,6 +876,16 @@ def visitError_path_decl_path(self, ctx: ASLParser.Error_path_decl_pathContext) path: str = self._inner_string_of(parse_tree=ctx.STRINGPATH()) return ErrorPathJsonPath(value=path) + def visitError_path_decl_context( + self, ctx: ASLParser.Error_path_decl_contextContext + ) -> ErrorDecl: + self._raise_if_query_language_is_not( + query_language_mode=QueryLanguageMode.JSONPath, ctx=ctx + ) + path = self._inner_string_of(parse_tree=ctx.STRINGPATHCONTEXTOBJ()) + path_tail = path[1:] + return ErrorPathContextObject(path_tail) + def visitError_path_decl_intrinsic( self, ctx: ASLParser.Error_path_decl_intrinsicContext ) -> ErrorDecl: @@ -906,6 +918,16 @@ def visitCause_path_decl_path(self, ctx: ASLParser.Cause_path_decl_pathContext) path: str = self._inner_string_of(parse_tree=ctx.STRINGPATH()) return CausePathJsonPath(value=path) + def visitCause_path_decl_context( + self, ctx: ASLParser.Cause_path_decl_contextContext + ) -> CauseDecl: + self._raise_if_query_language_is_not( + query_language_mode=QueryLanguageMode.JSONPath, ctx=ctx + ) + path = self._inner_string_of(parse_tree=ctx.STRINGPATHCONTEXTOBJ()) + path_tail = path[1:] + return CausePathContextObject(path_tail) + def visitCause_path_decl_intrinsic( self, ctx: ASLParser.Cause_path_decl_intrinsicContext ) -> CauseDecl: diff --git a/tests/aws/services/stepfunctions/templates/context_object/context_object_templates.py b/tests/aws/services/stepfunctions/templates/context_object/context_object_templates.py index 6c64cef79bd67..056a921e02333 100644 --- a/tests/aws/services/stepfunctions/templates/context_object/context_object_templates.py +++ b/tests/aws/services/stepfunctions/templates/context_object/context_object_templates.py @@ -9,6 +9,9 @@ class ContextObjectTemplates(TemplateLoader): CONTEXT_OBJECT_LITERAL_PLACEHOLDER = "%CONTEXT_OBJECT_LITERAL_PLACEHOLDER%" + CONTEXT_OBJECT_ERROR_CAUSE_PATH: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/context_object_error_cause_path.json5" + ) CONTEXT_OBJECT_INPUT_PATH: Final[str] = os.path.join( _THIS_FOLDER, "statemachines/context_object_input_path.json5" ) diff --git a/tests/aws/services/stepfunctions/templates/context_object/statemachines/context_object_error_cause_path.json5 b/tests/aws/services/stepfunctions/templates/context_object/statemachines/context_object_error_cause_path.json5 new file mode 100644 index 0000000000000..96cbb1956c17e --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/context_object/statemachines/context_object_error_cause_path.json5 @@ -0,0 +1,10 @@ +{ + "StartAt": "StartState", + "States": { + "StartState": { + "Type": "Fail", + "ErrorPath": "$$.State.Name", + "CausePath": "$$.StateMachine.Name" + } + } +} \ No newline at end of file diff --git a/tests/aws/services/stepfunctions/v2/context_object/test_context_object.py b/tests/aws/services/stepfunctions/v2/context_object/test_context_object.py index 02c2b89fa3078..7807bb0d1371f 100644 --- a/tests/aws/services/stepfunctions/v2/context_object/test_context_object.py +++ b/tests/aws/services/stepfunctions/v2/context_object/test_context_object.py @@ -18,7 +18,6 @@ @markers.snapshot.skip_snapshot_verify( paths=[ - "$..tracingConfiguration", "$..RedriveCount", "$..RedriveStatus", "$..SdkHttpMetadata", @@ -142,7 +141,7 @@ def test_variable( ) @markers.aws.validated - def test_items_path( + def test_error_cause_path( self, aws_client, create_iam_role_for_sfn, @@ -150,14 +149,10 @@ def test_items_path( sfn_snapshot, ): template = ContextObjectTemplates.load_sfn_template( - ContextObjectTemplates.CONTEXT_OBJECT_ITEMS_PATH + ContextObjectTemplates.CONTEXT_OBJECT_ERROR_CAUSE_PATH ) definition = json.dumps(template) - definition = definition.replace( - ContextObjectTemplates.CONTEXT_OBJECT_LITERAL_PLACEHOLDER, - "$$.Execution.Input.input-values", - ) - exec_input = json.dumps({"input-values": ["item-0"]}) + exec_input = json.dumps({}) create_and_record_execution( aws_client.stepfunctions, create_iam_role_for_sfn, diff --git a/tests/aws/services/stepfunctions/v2/context_object/test_context_object.snapshot.json b/tests/aws/services/stepfunctions/v2/context_object/test_context_object.snapshot.json index 1b52f8be224ba..e5b725260d38d 100644 --- a/tests/aws/services/stepfunctions/v2/context_object/test_context_object.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/context_object/test_context_object.snapshot.json @@ -872,5 +872,54 @@ } } } + }, + "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_error_cause_path": { + "recorded-date": "28-11-2024, 14:56:32", + "recorded-content": { + "get_execution_history": { + "events": [ + { + "executionStartedEventDetails": { + "input": {}, + "inputDetails": { + "truncated": false + }, + "roleArn": "snf_role_arn" + }, + "id": 1, + "previousEventId": 0, + "timestamp": "timestamp", + "type": "ExecutionStarted" + }, + { + "id": 2, + "previousEventId": 0, + "stateEnteredEventDetails": { + "input": {}, + "inputDetails": { + "truncated": false + }, + "name": "StartState" + }, + "timestamp": "timestamp", + "type": "FailStateEntered" + }, + { + "executionFailedEventDetails": { + "cause": "", + "error": "StartState" + }, + "id": 3, + "previousEventId": 2, + "timestamp": "timestamp", + "type": "ExecutionFailed" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/stepfunctions/v2/context_object/test_context_object.validation.json b/tests/aws/services/stepfunctions/v2/context_object/test_context_object.validation.json index f0442ef6915c4..c65f96577476e 100644 --- a/tests/aws/services/stepfunctions/v2/context_object/test_context_object.validation.json +++ b/tests/aws/services/stepfunctions/v2/context_object/test_context_object.validation.json @@ -1,4 +1,7 @@ { + "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_error_cause_path": { + "last_validated_date": "2024-11-28T14:56:32+00:00" + }, "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_input_path[$$.Execution.Input]": { "last_validated_date": "2024-09-11T12:47:13+00:00" }, From 1bd7dca4d8667b265b76b6a514f7c9d5fec547b0 Mon Sep 17 00:00:00 2001 From: Greg Furman <31275503+gregfurman@users.noreply.github.com> Date: Fri, 29 Nov 2024 16:43:38 +0200 Subject: [PATCH 32/38] [SFN] Add usage analytics for Variable Workflow and JSONata features (#11963) --- .../usage_metrics_static_analyser.py | 52 ++++++++++ .../services/stepfunctions/provider.py | 7 ++ .../services/stepfunctions/usage.py | 20 ++++ .../test_base_evaluate_expressions.py | 8 +- .../test_usage_metrics_static_analyser.py | 96 +++++++++++++++++++ 5 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 localstack-core/localstack/services/stepfunctions/asl/static_analyser/usage_metrics_static_analyser.py create mode 100644 localstack-core/localstack/services/stepfunctions/usage.py create mode 100644 tests/unit/services/stepfunctions/test_usage_metrics_static_analyser.py diff --git a/localstack-core/localstack/services/stepfunctions/asl/static_analyser/usage_metrics_static_analyser.py b/localstack-core/localstack/services/stepfunctions/asl/static_analyser/usage_metrics_static_analyser.py new file mode 100644 index 0000000000000..dc40998e96c1f --- /dev/null +++ b/localstack-core/localstack/services/stepfunctions/asl/static_analyser/usage_metrics_static_analyser.py @@ -0,0 +1,52 @@ +import logging + +import localstack.services.stepfunctions.usage as UsageMetrics +from localstack.services.stepfunctions.asl.antlr.runtime.ASLParser import ASLParser +from localstack.services.stepfunctions.asl.component.common.query_language import ( + QueryLanguageMode, +) +from localstack.services.stepfunctions.asl.static_analyser.static_analyser import StaticAnalyser + +LOG = logging.getLogger(__name__) + + +class UsageMetricsStaticAnalyser(StaticAnalyser): + @staticmethod + def process(definition: str) -> "UsageMetricsStaticAnalyser": + analyser = UsageMetricsStaticAnalyser() + try: + analyser.analyse(definition=definition) + + if analyser.has_jsonata: + UsageMetrics.jsonata_create_counter.increment() + else: + UsageMetrics.jsonpath_create_counter.increment() + + if analyser.has_variable_sampling: + UsageMetrics.variables_create_counter.increment() + except Exception as e: + LOG.warning( + "Failed to record Step Functions metrics from static analysis", + exc_info=e, + ) + return analyser + + def __init__(self): + super().__init__() + self.has_jsonata: bool = False + self.has_variable_sampling = False + + def visitQuery_language_decl(self, ctx: ASLParser.Query_language_declContext): + if self.has_jsonata: + return + + query_language_mode_int = ctx.children[-1].getSymbol().type + query_language_mode = QueryLanguageMode(value=query_language_mode_int) + if query_language_mode == QueryLanguageMode.JSONata: + self.has_jsonata = True + + def visitVariable_sample(self, ctx: ASLParser.Variable_sampleContext): + self.has_variable_sampling = True + + def visitAssign_decl(self, ctx: ASLParser.Assign_declContext): + self.has_variable_sampling = True diff --git a/localstack-core/localstack/services/stepfunctions/provider.py b/localstack-core/localstack/services/stepfunctions/provider.py index 690dd68f8b43b..d08c9c1c5bc15 100644 --- a/localstack-core/localstack/services/stepfunctions/provider.py +++ b/localstack-core/localstack/services/stepfunctions/provider.py @@ -125,6 +125,9 @@ from localstack.services.stepfunctions.asl.static_analyser.test_state.test_state_analyser import ( TestStateStaticAnalyser, ) +from localstack.services.stepfunctions.asl.static_analyser.usage_metrics_static_analyser import ( + UsageMetricsStaticAnalyser, +) from localstack.services.stepfunctions.backend.activity import Activity, ActivityTask from localstack.services.stepfunctions.backend.execution import Execution, SyncExecution from localstack.services.stepfunctions.backend.state_machine import ( @@ -481,6 +484,9 @@ def create_state_machine( state_machines[state_machine_version_arn] = state_machine_version create_output["stateMachineVersionArn"] = state_machine_version_arn + # Run static analyser on definition and collect usage metrics + UsageMetricsStaticAnalyser.process(state_machine_definition) + return create_output def describe_state_machine( @@ -974,6 +980,7 @@ def update_state_machine( if not isinstance(state_machine, StateMachineRevision): self._raise_state_machine_does_not_exist(state_machine_arn) + # TODO: Add logic to handle metrics for when SFN definitions update if not any([definition, role_arn, logging_configuration]): raise MissingRequiredParameter( "Either the definition, the role ARN, the LoggingConfiguration, " diff --git a/localstack-core/localstack/services/stepfunctions/usage.py b/localstack-core/localstack/services/stepfunctions/usage.py new file mode 100644 index 0000000000000..8d5e9391f3147 --- /dev/null +++ b/localstack-core/localstack/services/stepfunctions/usage.py @@ -0,0 +1,20 @@ +""" +Usage reporting for StepFunctions service +""" + +from localstack.utils.analytics.usage import UsageCounter + +# Count of StepFunctions being created with JSONata QueryLanguage +jsonata_create_counter = UsageCounter("stepfunctions:jsonata:create") + +# Count of StepFunctions being created with JSONPath QueryLanguage +jsonpath_create_counter = UsageCounter("stepfunctions:jsonpath:create") + +# Count of StepFunctions being created that use Variable Sampling or the Assign block +variables_create_counter = UsageCounter("stepfunctions:variables:create") + +# Successful invocations (also including expected error cases in line with AWS behaviour) +invocation_counter = UsageCounter("stepfunctions:invocation") + +# Unexpected errors that we do not account for +error_counter = UsageCounter("stepfunctions:error") diff --git a/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py b/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py index 83dd46d6713cb..5e6be999b94c1 100644 --- a/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py +++ b/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py @@ -36,7 +36,13 @@ class TestBaseEvaluateJsonata: @pytest.mark.parametrize( "expression_dict", [ - {"TimeoutSeconds": EJT.JSONATA_NUMBER_EXPRESSION}, + pytest.param( + {"TimeoutSeconds": EJT.JSONATA_NUMBER_EXPRESSION}, + marks=pytest.mark.skipif( + condition=not is_aws_cloud(), + reason="Polling and timeouts are flakey.", + ), + ), {"HeartbeatSeconds": EJT.JSONATA_NUMBER_EXPRESSION}, ], ids=[ diff --git a/tests/unit/services/stepfunctions/test_usage_metrics_static_analyser.py b/tests/unit/services/stepfunctions/test_usage_metrics_static_analyser.py new file mode 100644 index 0000000000000..fc1e457d477be --- /dev/null +++ b/tests/unit/services/stepfunctions/test_usage_metrics_static_analyser.py @@ -0,0 +1,96 @@ +import json + +import pytest + +from localstack.services.stepfunctions.asl.static_analyser.usage_metrics_static_analyser import ( + UsageMetricsStaticAnalyser, +) +from tests.aws.services.stepfunctions.templates.assign.assign_templates import ( + AssignTemplate, +) +from tests.aws.services.stepfunctions.templates.querylanguage.query_language_templates import ( + QueryLanguageTemplate, +) + + +class TestUsageMetricsStaticAnalyser: + @staticmethod + def _get_query_language_definition(query_language_template_filepath: str) -> str: + template = QueryLanguageTemplate.load_sfn_template(query_language_template_filepath) + definition = json.dumps(template) + return definition + + @staticmethod + def _get_variable_sampling_definition(variable_sampling_template_filepath: str) -> str: + template = AssignTemplate.load_sfn_template(variable_sampling_template_filepath) + definition = json.dumps(template) + return definition + + @pytest.mark.parametrize( + "template_filepath", + [ + QueryLanguageTemplate.BASE_PASS_JSONATA, + QueryLanguageTemplate.BASE_PASS_JSONATA_OVERRIDE, + QueryLanguageTemplate.BASE_PASS_JSONATA_OVERRIDE_DEFAULT, + ], + ids=[ + "BASE_PASS_JSONATA", + "BASE_PASS_JSONATA_OVERRIDE", + "BASE_PASS_JSONATA_OVERRIDE_DEFAULT", + ], + ) + def test_jsonata(self, template_filepath): + definition = self._get_query_language_definition(template_filepath) + analyser = UsageMetricsStaticAnalyser.process(definition) + assert analyser.has_jsonata + assert not analyser.has_variable_sampling + + @pytest.mark.parametrize( + "template_filepath", + [ + QueryLanguageTemplate.BASE_PASS_JSONPATH, + ], + ids=["BASE_PASS_JSONPATH"], + ) + def test_jsonpath(self, template_filepath): + definition = self._get_query_language_definition(template_filepath) + analyser = UsageMetricsStaticAnalyser.process(definition) + assert not analyser.has_jsonata + assert not analyser.has_variable_sampling + + @pytest.mark.parametrize( + "template_filepath", + [ + QueryLanguageTemplate.JSONPATH_TO_JSONATA_DATAFLOW, + QueryLanguageTemplate.JSONPATH_ASSIGN_JSONATA_REF, + ], + ids=["JSONPATH_TO_JSONATA_DATAFLOW", "JSONPATH_ASSIGN_JSONATA_REF"], + ) + def test_jsonata_and_variable_sampling(self, template_filepath): + definition = self._get_query_language_definition(template_filepath) + analyser = UsageMetricsStaticAnalyser.process(definition) + assert analyser.has_jsonata + assert analyser.has_variable_sampling + + @pytest.mark.parametrize( + "template_filepath", + [ + AssignTemplate.BASE_EMPTY, + AssignTemplate.BASE_PATHS, + AssignTemplate.BASE_SCOPE_MAP, + AssignTemplate.BASE_ASSIGN_FROM_LAMBDA_TASK_RESULT, + AssignTemplate.BASE_REFERENCE_IN_LAMBDA_TASK_FIELDS, + ], + ids=[ + "BASE_EMPTY", + "BASE_PATHS", + "BASE_SCOPE_MAP", + "BASE_ASSIGN_FROM_LAMBDA_TASK_RESULT", + "BASE_REFERENCE_IN_LAMBDA_TASK_FIELDS", + ], + ) + def test_jsonpath_and_variable_sampling(self, template_filepath): + definition = self._get_query_language_definition(template_filepath) + analyser = UsageMetricsStaticAnalyser.process(definition) + assert not analyser.has_jsonata + assert analyser.has_variable_sampling From 55295bfd142f72a6d0f1201db95609e81d6cf09f Mon Sep 17 00:00:00 2001 From: Greg Furman <31275503+gregfurman@users.noreply.github.com> Date: Fri, 29 Nov 2024 17:15:51 +0200 Subject: [PATCH 33/38] [ESM] Fix polling of SQS queue when batch size exceeds 10 (#11945) --- .../pollers/sqs_poller.py | 4 +- .../test_lambda_integration_sqs.py | 179 +- .../test_lambda_integration_sqs.snapshot.json | 2026 +++++++++++++++++ ...est_lambda_integration_sqs.validation.json | 19 +- ...ambda_event_source_mapping_send_message.py | 21 + tests/aws/services/lambda_/test_lambda.py | 3 + 6 files changed, 2248 insertions(+), 4 deletions(-) create mode 100644 tests/aws/services/lambda_/functions/lambda_event_source_mapping_send_message.py diff --git a/localstack-core/localstack/services/lambda_/event_source_mapping/pollers/sqs_poller.py b/localstack-core/localstack/services/lambda_/event_source_mapping/pollers/sqs_poller.py index 65953f13bd263..58ffa05d752e6 100644 --- a/localstack-core/localstack/services/lambda_/event_source_mapping/pollers/sqs_poller.py +++ b/localstack-core/localstack/services/lambda_/event_source_mapping/pollers/sqs_poller.py @@ -66,7 +66,9 @@ def poll_events(self) -> None: # https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-pipes-sqs.html#pipes-sqs-scaling response = self.source_client.receive_message( QueueUrl=self.queue_url, - MaxNumberOfMessages=self.sqs_queue_parameters["BatchSize"], + MaxNumberOfMessages=min( + self.sqs_queue_parameters["BatchSize"], DEFAULT_MAX_RECEIVE_COUNT + ), # BatchSize cannot exceed 10 MessageAttributeNames=["All"], MessageSystemAttributeNames=[MessageSystemAttributeName.All], ) diff --git a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py index 661364033a2a9..e45ad2f045a55 100644 --- a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py +++ b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py @@ -3,7 +3,7 @@ import pytest from botocore.exceptions import ClientError -from localstack_snapshot.snapshots.transformer import KeyValueBasedTransformer +from localstack_snapshot.snapshots.transformer import KeyValueBasedTransformer, SortingTransformer from localstack import config from localstack.aws.api.lambda_ import InvalidParameterValueException, Runtime @@ -15,6 +15,7 @@ from localstack.utils.testutil import check_expected_lambda_log_events_length, get_lambda_log_events from tests.aws.services.lambda_.functions import FUNCTIONS_PATH, lambda_integration from tests.aws.services.lambda_.test_lambda import ( + TEST_LAMBDA_EVENT_SOURCE_MAPPING_SEND_MESSAGE, TEST_LAMBDA_PYTHON, TEST_LAMBDA_PYTHON_ECHO, TEST_LAMBDA_PYTHON_ECHO_VERSION_ENV, @@ -1042,6 +1043,182 @@ def test_sqs_event_source_mapping( rs = aws_client.sqs.receive_message(QueueUrl=queue_url_1) assert rs.get("Messages", []) == [] + @pytest.mark.parametrize("batch_size", [15, 100, 1_000, 10_000]) + @markers.aws.validated + def test_sqs_event_source_mapping_batch_size( + self, + create_lambda_function, + sqs_create_queue, + sqs_get_queue_arn, + lambda_su_role, + snapshot, + cleanups, + aws_client, + batch_size, + ): + snapshot.add_transformer(snapshot.transform.sqs_api()) + snapshot.add_transformer(SortingTransformer("Records", lambda s: s["body"]), priority=-1) + + destination_queue_name = f"destination-queue-{short_uid()}" + function_name = f"lambda_func-{short_uid()}" + source_queue_name = f"source-queue-{short_uid()}" + mapping_uuid = None + + destination_queue_url = sqs_create_queue(QueueName=destination_queue_name) + create_lambda_function( + func_name=function_name, + handler_file=TEST_LAMBDA_EVENT_SOURCE_MAPPING_SEND_MESSAGE, + runtime=Runtime.python3_12, + envvars={"SQS_QUEUE_URL": destination_queue_url}, + role=lambda_su_role, + ) + + queue_url = sqs_create_queue(QueueName=source_queue_name) + queue_arn = sqs_get_queue_arn(queue_url) + + create_event_source_mapping_response = aws_client.lambda_.create_event_source_mapping( + EventSourceArn=queue_arn, + FunctionName=function_name, + MaximumBatchingWindowInSeconds=10 if is_aws_cloud() else 2, + BatchSize=batch_size, + ) + mapping_uuid = create_event_source_mapping_response["UUID"] + cleanups.append(lambda: aws_client.lambda_.delete_event_source_mapping(UUID=mapping_uuid)) + snapshot.match("create-event-source-mapping-response", create_event_source_mapping_response) + _await_event_source_mapping_enabled(aws_client.lambda_, mapping_uuid) + + reponse_batch_send_10 = aws_client.sqs.send_message_batch( + QueueUrl=queue_url, + Entries=[{"Id": f"{i}-0", "MessageBody": f"{i}-0-message-{i}"} for i in range(10)], + ) + snapshot.match("send-message-batch-result-10", reponse_batch_send_10) + + reponse_batch_send_5 = aws_client.sqs.send_message_batch( + QueueUrl=queue_url, + Entries=[{"Id": f"{i}-1", "MessageBody": f"{i}-1-message-{i}"} for i in range(5)], + ) + snapshot.match("send-message-batch-result-5", reponse_batch_send_5) + + batches = [] + + def get_msg_from_q(): + messages_to_delete = [] + receive_message_response = aws_client.sqs.receive_message( + QueueUrl=destination_queue_url, + MaxNumberOfMessages=10, + VisibilityTimeout=120, + WaitTimeSeconds=5 if is_aws_cloud() else 1, + ) + messages = receive_message_response.get("Messages", []) + for message in messages: + received_batch = json.loads(message["Body"]) + batches.append(received_batch) + messages_to_delete.append( + {"Id": message["MessageId"], "ReceiptHandle": message["ReceiptHandle"]} + ) + + aws_client.sqs.delete_message_batch( + QueueUrl=destination_queue_url, Entries=messages_to_delete + ) + assert sum([len(batch) for batch in batches]) == 15 + return [message for batch in batches for message in batch] + + events = retry(get_msg_from_q, retries=15, sleep=5) + snapshot.match("Records", events) + + # FIXME: this fails due to ESM not correctly collecting and sending batches + # where size exceeds 10 messages. + @markers.snapshot.skip_snapshot_verify(paths=["$..total_batches_received"]) + @markers.aws.validated + def test_sqs_event_source_mapping_batching_reserved_concurrency( + self, + create_lambda_function, + sqs_create_queue, + sqs_get_queue_arn, + lambda_su_role, + snapshot, + cleanups, + aws_client, + ): + snapshot.add_transformer(snapshot.transform.sqs_api()) + snapshot.add_transformer(SortingTransformer("Records", lambda s: s["body"]), priority=-1) + + destination_queue_name = f"destination-queue-{short_uid()}" + function_name = f"lambda_func-{short_uid()}" + source_queue_name = f"source-queue-{short_uid()}" + mapping_uuid = None + + destination_queue_url = sqs_create_queue(QueueName=destination_queue_name) + create_lambda_function( + func_name=function_name, + handler_file=TEST_LAMBDA_EVENT_SOURCE_MAPPING_SEND_MESSAGE, + runtime=Runtime.python3_12, + envvars={"SQS_QUEUE_URL": destination_queue_url}, + role=lambda_su_role, + ) + + # Prevent more than 2 Lambdas from being spun up at a time + put_concurrency_resp = aws_client.lambda_.put_function_concurrency( + FunctionName=function_name, ReservedConcurrentExecutions=2 + ) + snapshot.match("put_concurrency_resp", put_concurrency_resp) + + queue_url = sqs_create_queue(QueueName=source_queue_name) + queue_arn = sqs_get_queue_arn(queue_url) + + create_event_source_mapping_response = aws_client.lambda_.create_event_source_mapping( + EventSourceArn=queue_arn, + FunctionName=function_name, + MaximumBatchingWindowInSeconds=10, + BatchSize=20, + ScalingConfig={ + "MaximumConcurrency": 2 + }, # Prevent more than 2 concurrent SQS workers from being spun up at a time + ) + mapping_uuid = create_event_source_mapping_response["UUID"] + cleanups.append(lambda: aws_client.lambda_.delete_event_source_mapping(UUID=mapping_uuid)) + snapshot.match("create-event-source-mapping-response", create_event_source_mapping_response) + _await_event_source_mapping_enabled(aws_client.lambda_, mapping_uuid) + + for b in range(3): + aws_client.sqs.send_message_batch( + QueueUrl=queue_url, + Entries=[{"Id": f"{i}-{b}", "MessageBody": f"{i}-{b}-message"} for i in range(10)], + ) + + batches = [] + + def get_msg_from_q(): + messages_to_delete = [] + receive_message_response = aws_client.sqs.receive_message( + QueueUrl=destination_queue_url, + MaxNumberOfMessages=10, + VisibilityTimeout=120, + WaitTimeSeconds=5, + ) + messages = receive_message_response.get("Messages", []) + for message in messages: + received_batch = json.loads(message["Body"]) + batches.append(received_batch) + messages_to_delete.append( + {"Id": message["MessageId"], "ReceiptHandle": message["ReceiptHandle"]} + ) + + if messages_to_delete: + aws_client.sqs.delete_message_batch( + QueueUrl=destination_queue_url, Entries=messages_to_delete + ) + assert sum([len(batch) for batch in batches]) == 30 + return [message for batch in batches for message in batch] + + events = retry(get_msg_from_q, retries=15, sleep=5) + + # We expect to receive 2 batches where each batch contains some proportion of the + # 30 messages we sent through, divided by the 20 ESM batch size. How this is split is + # not determinable a priori so rather just snapshots the events and the no. of batches. + snapshot.match("batch_info", {"total_batches_received": len(batches)}) + snapshot.match("Records", events) + @markers.aws.validated @pytest.mark.parametrize( "filter, item_matching, item_not_matching", diff --git a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.snapshot.json b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.snapshot.json index dd4bf781ada96..7ff32c8fd5937 100644 --- a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.snapshot.json +++ b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.snapshot.json @@ -1662,5 +1662,2031 @@ } } } + }, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[15]": { + "recorded-date": "26-11-2024, 13:43:42", + "recorded-content": { + "create-event-source-mapping-response": { + "BatchSize": 15, + "EventSourceArn": "arn::sqs::111111111111:", + "EventSourceMappingArn": "arn::lambda::111111111111:event-source-mapping:", + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionResponseTypes": [], + "LastModified": "", + "MaximumBatchingWindowInSeconds": 10, + "State": "Creating", + "StateTransitionReason": "USER_INITIATED", + "UUID": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 202 + } + }, + "send-message-batch-result-10": { + "Successful": [ + { + "Id": "0-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "1-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "2-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "3-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "4-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "5-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "6-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "7-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "8-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "9-0", + "MD5OfMessageBody": "", + "MessageId": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "send-message-batch-result-5": { + "Successful": [ + { + "Id": "0-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "1-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "2-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "3-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "4-1", + "MD5OfMessageBody": "", + "MessageId": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "Records": [ + { + "messageId": "", + "receiptHandle": "", + "body": "0-0-message-0", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "0-1-message-0", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "1-0-message-1", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfBody": "", + "md5OfMessageAttributes": null, + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "1-1-message-1", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "2-0-message-2", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfBody": "", + "md5OfMessageAttributes": null, + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "2-1-message-2", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "3-0-message-3", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "3-1-message-3", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "4-0-message-4", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "4-1-message-4", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "5-0-message-5", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "6-0-message-6", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "7-0-message-7", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "8-0-message-8", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "9-0-message-9", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + } + ] + } + }, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batching_reserved_concurrency": { + "recorded-date": "29-11-2024, 13:29:56", + "recorded-content": { + "put_concurrency_resp": { + "ReservedConcurrentExecutions": 2, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create-event-source-mapping-response": { + "BatchSize": 20, + "EventSourceArn": "arn::sqs::111111111111:", + "EventSourceMappingArn": "arn::lambda::111111111111:event-source-mapping:", + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionResponseTypes": [], + "LastModified": "", + "MaximumBatchingWindowInSeconds": 10, + "ScalingConfig": { + "MaximumConcurrency": 2 + }, + "State": "Creating", + "StateTransitionReason": "USER_INITIATED", + "UUID": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 202 + } + }, + "batch_info": { + "total_batches_received": 2 + }, + "Records": [ + { + "messageId": "", + "receiptHandle": "", + "body": "0-0-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "0-1-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "0-2-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "1-0-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "1-1-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "1-2-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "2-0-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "2-1-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "2-2-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "3-0-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "3-1-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "3-2-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "4-0-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "4-1-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "4-2-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "5-0-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "5-1-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "5-2-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "6-0-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "6-1-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "6-2-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "7-0-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "7-1-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "7-2-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "8-0-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "8-1-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "8-2-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "9-0-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "9-1-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "9-2-message", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + } + ] + } + }, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[100]": { + "recorded-date": "26-11-2024, 13:44:40", + "recorded-content": { + "create-event-source-mapping-response": { + "BatchSize": 100, + "EventSourceArn": "arn::sqs::111111111111:", + "EventSourceMappingArn": "arn::lambda::111111111111:event-source-mapping:", + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionResponseTypes": [], + "LastModified": "", + "MaximumBatchingWindowInSeconds": 10, + "State": "Creating", + "StateTransitionReason": "USER_INITIATED", + "UUID": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 202 + } + }, + "send-message-batch-result-10": { + "Successful": [ + { + "Id": "0-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "1-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "2-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "3-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "4-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "5-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "6-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "7-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "8-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "9-0", + "MD5OfMessageBody": "", + "MessageId": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "send-message-batch-result-5": { + "Successful": [ + { + "Id": "0-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "1-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "2-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "3-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "4-1", + "MD5OfMessageBody": "", + "MessageId": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "Records": [ + { + "messageId": "", + "receiptHandle": "", + "body": "0-0-message-0", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfBody": "", + "md5OfMessageAttributes": null, + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "0-1-message-0", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "1-0-message-1", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfBody": "", + "md5OfMessageAttributes": null, + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "1-1-message-1", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfBody": "", + "md5OfMessageAttributes": null, + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "2-0-message-2", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfBody": "", + "md5OfMessageAttributes": null, + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "2-1-message-2", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "3-0-message-3", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfBody": "", + "md5OfMessageAttributes": null, + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "3-1-message-3", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfBody": "", + "md5OfMessageAttributes": null, + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "4-0-message-4", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfBody": "", + "md5OfMessageAttributes": null, + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "4-1-message-4", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfBody": "", + "md5OfMessageAttributes": null, + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "5-0-message-5", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "6-0-message-6", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "7-0-message-7", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfBody": "", + "md5OfMessageAttributes": null, + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "8-0-message-8", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "9-0-message-9", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfBody": "", + "md5OfMessageAttributes": null, + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + } + ] + } + }, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[1000]": { + "recorded-date": "26-11-2024, 13:45:41", + "recorded-content": { + "create-event-source-mapping-response": { + "BatchSize": 1000, + "EventSourceArn": "arn::sqs::111111111111:", + "EventSourceMappingArn": "arn::lambda::111111111111:event-source-mapping:", + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionResponseTypes": [], + "LastModified": "", + "MaximumBatchingWindowInSeconds": 10, + "State": "Creating", + "StateTransitionReason": "USER_INITIATED", + "UUID": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 202 + } + }, + "send-message-batch-result-10": { + "Successful": [ + { + "Id": "0-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "1-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "2-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "3-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "4-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "5-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "6-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "7-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "8-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "9-0", + "MD5OfMessageBody": "", + "MessageId": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "send-message-batch-result-5": { + "Successful": [ + { + "Id": "0-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "1-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "2-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "3-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "4-1", + "MD5OfMessageBody": "", + "MessageId": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "Records": [ + { + "messageId": "", + "receiptHandle": "", + "body": "0-0-message-0", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "0-1-message-0", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "1-0-message-1", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "1-1-message-1", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "2-0-message-2", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "2-1-message-2", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "3-0-message-3", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "3-1-message-3", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "4-0-message-4", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "4-1-message-4", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "5-0-message-5", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "6-0-message-6", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "7-0-message-7", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "8-0-message-8", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "9-0-message-9", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + } + ] + } + }, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[10000]": { + "recorded-date": "26-11-2024, 13:46:48", + "recorded-content": { + "create-event-source-mapping-response": { + "BatchSize": 10000, + "EventSourceArn": "arn::sqs::111111111111:", + "EventSourceMappingArn": "arn::lambda::111111111111:event-source-mapping:", + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionResponseTypes": [], + "LastModified": "", + "MaximumBatchingWindowInSeconds": 10, + "State": "Creating", + "StateTransitionReason": "USER_INITIATED", + "UUID": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 202 + } + }, + "send-message-batch-result-10": { + "Successful": [ + { + "Id": "0-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "1-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "2-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "3-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "4-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "5-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "6-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "7-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "8-0", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "9-0", + "MD5OfMessageBody": "", + "MessageId": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "send-message-batch-result-5": { + "Successful": [ + { + "Id": "0-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "1-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "2-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "3-1", + "MD5OfMessageBody": "", + "MessageId": "" + }, + { + "Id": "4-1", + "MD5OfMessageBody": "", + "MessageId": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "Records": [ + { + "messageId": "", + "receiptHandle": "", + "body": "0-0-message-0", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "0-1-message-0", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "1-0-message-1", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "1-1-message-1", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "2-0-message-2", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "2-1-message-2", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "3-0-message-3", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "3-1-message-3", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "4-0-message-4", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "4-1-message-4", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "5-0-message-5", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "6-0-message-6", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "7-0-message-7", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "8-0-message-8", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + }, + { + "messageId": "", + "receiptHandle": "", + "body": "9-0-message-9", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "sent-timestamp", + "SenderId": "", + "ApproximateFirstReceiveTimestamp": "" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": null, + "md5OfBody": "", + "eventSource": "aws:sqs", + "eventSourceARN": "arn::sqs::111111111111:", + "awsRegion": "" + } + ] + } + }, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batching_behaviour[100]": { + "recorded-date": "26-11-2024, 14:23:08", + "recorded-content": {} } } diff --git a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.validation.json b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.validation.json index 0db9001a189f1..78db21ed15025 100644 --- a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.validation.json +++ b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.validation.json @@ -30,7 +30,22 @@ "last_validated_date": "2024-10-12T13:43:31+00:00" }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping": { - "last_validated_date": "2024-10-12T13:38:01+00:00" + "last_validated_date": "2024-11-25T15:46:54+00:00" + }, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[10000]": { + "last_validated_date": "2024-11-26T13:46:45+00:00" + }, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[1000]": { + "last_validated_date": "2024-11-26T13:45:39+00:00" + }, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[100]": { + "last_validated_date": "2024-11-26T13:44:38+00:00" + }, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[15]": { + "last_validated_date": "2024-11-26T13:43:39+00:00" + }, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batching_reserved_concurrency": { + "last_validated_date": "2024-11-29T13:29:53+00:00" }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_update": { "last_validated_date": "2024-10-12T13:45:43+00:00" @@ -48,7 +63,7 @@ "last_validated_date": "2024-10-12T13:43:40+00:00" }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_failing_lambda_retries_after_visibility_timeout": { - "last_validated_date": "2024-10-12T13:32:29+00:00" + "last_validated_date": "2024-11-25T12:12:47+00:00" }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_fifo_message_group_parallelism": { "last_validated_date": "2024-10-12T13:37:00+00:00" diff --git a/tests/aws/services/lambda_/functions/lambda_event_source_mapping_send_message.py b/tests/aws/services/lambda_/functions/lambda_event_source_mapping_send_message.py new file mode 100644 index 0000000000000..6ce293c92fe2f --- /dev/null +++ b/tests/aws/services/lambda_/functions/lambda_event_source_mapping_send_message.py @@ -0,0 +1,21 @@ +import json +import os + +import boto3 + + +def handler(event, context): + endpoint_url = os.environ.get("AWS_ENDPOINT_URL") + + region_name = ( + os.environ.get("AWS_DEFAULT_REGION") or os.environ.get("AWS_REGION") or "us-east-1" + ) + + sqs = boto3.client("sqs", endpoint_url=endpoint_url, verify=False, region_name=region_name) + + queue_url = os.environ.get("SQS_QUEUE_URL") + + records = event.get("Records", []) + sqs.send_message(QueueUrl=queue_url, MessageBody=json.dumps(records)) + + return {"count": len(records)} diff --git a/tests/aws/services/lambda_/test_lambda.py b/tests/aws/services/lambda_/test_lambda.py index 4127352842a26..d1a621229b0b4 100644 --- a/tests/aws/services/lambda_/test_lambda.py +++ b/tests/aws/services/lambda_/test_lambda.py @@ -101,6 +101,9 @@ ) TEST_LAMBDA_ENV = os.path.join(THIS_FOLDER, "functions/lambda_environment.py") +TEST_LAMBDA_EVENT_SOURCE_MAPPING_SEND_MESSAGE = os.path.join( + THIS_FOLDER, "functions/lambda_event_source_mapping_send_message.py" +) TEST_LAMBDA_SEND_MESSAGE_FILE = os.path.join(THIS_FOLDER, "functions/lambda_send_message.py") TEST_LAMBDA_PUT_ITEM_FILE = os.path.join(THIS_FOLDER, "functions/lambda_put_item.py") TEST_LAMBDA_START_EXECUTION_FILE = os.path.join(THIS_FOLDER, "functions/lambda_start_execution.py") From d5b43de43aab49818952f0684002ad15e8423b1b Mon Sep 17 00:00:00 2001 From: Ben Simon Hartung <42031100+bentsku@users.noreply.github.com> Date: Fri, 29 Nov 2024 16:51:25 +0100 Subject: [PATCH 34/38] implement new native EventBridge EventRuleEngine (#11960) --- .../services/events/event_rule_engine.py | 568 +++++++++++++++ .../localstack/services/events/event_ruler.py | 6 +- .../localstack/services/events/provider.py | 15 +- .../localstack/services/events/v1/utils.py | 9 +- .../localstack/utils/event_matcher.py | 16 +- .../content_anything_but_ignorecase_EXC.json5 | 19 + ...ent_anything_but_ignorecase_list_EXC.json5 | 19 + .../content_anything_but_string_null.json5 | 19 + ...ntent_anything_prefix_ignorecase_EXC.json5 | 19 + .../content_anything_prefix_int_EXC.json5 | 19 + .../content_anything_prefix_list.json5 | 19 + .../content_anything_prefix_list_NEG.json5 | 19 + ...ontent_anything_prefix_list_type_EXC.json5 | 19 + ...ntent_anything_suffix_ignorecase_EXC.json5 | 19 + .../content_anything_suffix_int_EXC.json5 | 19 + .../content_anything_suffix_list.json5 | 19 + .../content_anything_suffix_list_NEG.json5 | 19 + ...ontent_anything_suffix_list_type_EXC.json5 | 19 + .../content_anything_wildcard.json5 | 19 + .../content_anything_wildcard_NEG.json5 | 19 + .../content_anything_wildcard_list.json5 | 19 + .../content_anything_wildcard_list_NEG.json5 | 19 + ...tent_anything_wildcard_list_type_EXC.json5 | 19 + .../content_anything_wildcard_type_EXC.json5 | 19 + .../content_ignorecase_EXC.json5 | 14 + .../content_ignorecase_list_EXC.json5 | 14 + .../content_ip_address_EXC.json5 | 19 + .../content_prefix_int_EXC.json5 | 14 + .../content_prefix_list_EXC.json5 | 14 + .../content_suffix_int_EXC.json5 | 15 + .../content_suffix_list_EXC.json5 | 15 + .../content_wildcard_int_EXC.json5 | 15 + .../content_wildcard_list_EXC.json5 | 15 + .../content_wildcard_repeating_star_EXC.json5 | 15 + .../services/events/test_events_patterns.py | 83 +-- .../events/test_events_patterns.snapshot.json | 656 +++++++++++++++--- .../test_events_patterns.validation.json | 279 +++++--- tests/unit/utils/test_event_matcher.py | 16 +- 38 files changed, 1918 insertions(+), 241 deletions(-) create mode 100644 localstack-core/localstack/services/events/event_rule_engine.py create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_list_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_but_string_null.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_prefix_ignorecase_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_prefix_int_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_prefix_list.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_NEG.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_type_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_suffix_ignorecase_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_suffix_int_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_suffix_list.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_NEG.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_type_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_wildcard.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_wildcard_NEG.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list_NEG.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list_type_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_anything_wildcard_type_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_ignorecase_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_ignorecase_list_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_ip_address_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_prefix_int_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_prefix_list_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_suffix_int_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_suffix_list_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_wildcard_int_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_wildcard_list_EXC.json5 create mode 100644 tests/aws/services/events/event_pattern_templates/content_wildcard_repeating_star_EXC.json5 diff --git a/localstack-core/localstack/services/events/event_rule_engine.py b/localstack-core/localstack/services/events/event_rule_engine.py new file mode 100644 index 0000000000000..1ac75985d9bc2 --- /dev/null +++ b/localstack-core/localstack/services/events/event_rule_engine.py @@ -0,0 +1,568 @@ +import ipaddress +import json +import re +import typing as t + +from localstack.aws.api.events import InvalidEventPatternException + + +class EventRuleEngine: + def evaluate_pattern_on_event(self, compiled_event_pattern: dict, event: str | dict): + if isinstance(event, str): + try: + body = json.loads(event) + if not isinstance(body, dict): + return False + except json.JSONDecodeError: + # Event pattern for the message body assume that the message payload is a well-formed JSON object. + return False + else: + body = event + + return self._evaluate_nested_event_pattern_on_dict(compiled_event_pattern, payload=body) + + def _evaluate_nested_event_pattern_on_dict(self, event_pattern, payload: dict) -> bool: + """ + This method evaluates the event pattern against the JSON decoded payload. + Although it's not documented anywhere, AWS allows `.` in the fields name in the event pattern and the payload, + and will evaluate them. However, it's not JSONPath compatible. + See: + https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-pattern.html#eb-create-pattern-considerations + Example: + Pattern: `{"field1.field2": "value1"}` + This pattern will match both `{"field1.field2": "value1"}` and {"field1: {"field2": "value1"}}`, unlike JSONPath + for which `.` points to a child node. + This might show they are flattening the both dictionaries to a single level for an easier matching without + recursion. + :param event_pattern: a dict, starting at the Event Pattern + :param payload: a dict, starting at the MessageBody + :return: True if the payload respect the event pattern, otherwise False + """ + if not event_pattern: + return True + + # TODO: maybe save/cache the flattened/expanded pattern? + flat_pattern_conditions = self.flatten_pattern(event_pattern) + flat_payloads = self.flatten_payload(payload) + + return any( + all( + any( + self._evaluate_condition( + flat_payload.get(key), condition, field_exists=key in flat_payload + ) + for condition in values + for flat_payload in flat_payloads + ) + for key, values in flat_pattern.items() + ) + for flat_pattern in flat_pattern_conditions + ) + + def _evaluate_condition(self, value, condition, field_exists: bool): + if not isinstance(condition, dict): + return field_exists and value == condition + elif (must_exist := condition.get("exists")) is not None: + # if must_exists is True then field_exists must be True + # if must_exists is False then fields_exists must be False + return must_exist == field_exists + elif anything_but := condition.get("anything-but"): + if isinstance(anything_but, dict): + if not_condition := anything_but.get("prefix"): + predicate = self._evaluate_prefix + elif not_condition := anything_but.get("suffix"): + predicate = self._evaluate_suffix + elif not_condition := anything_but.get("equals-ignore-case"): + predicate = self._evaluate_equal_ignore_case + elif not_condition := anything_but.get("wildcard"): + predicate = self._evaluate_wildcard + else: + # this should not happen as we validate the EventPattern before + return False + + if isinstance(not_condition, str): + return not predicate(not_condition, value) + elif isinstance(not_condition, list): + return all( + not predicate(sub_condition, value) for sub_condition in not_condition + ) + + elif isinstance(anything_but, list): + return value not in anything_but + else: + return value != anything_but + + elif value is None: + # the remaining conditions require the value to not be None + return False + elif prefix := condition.get("prefix"): + if isinstance(prefix, dict): + if prefix_equal_ignore_case := prefix.get("equals-ignore-case"): + return self._evaluate_prefix(prefix_equal_ignore_case.lower(), value.lower()) + else: + return self._evaluate_prefix(prefix, value) + + elif suffix := condition.get("suffix"): + if isinstance(suffix, dict): + if suffix_equal_ignore_case := suffix.get("equals-ignore-case"): + return self._evaluate_suffix(suffix_equal_ignore_case.lower(), value.lower()) + else: + return self._evaluate_suffix(suffix, value) + + elif equal_ignore_case := condition.get("equals-ignore-case"): + return self._evaluate_equal_ignore_case(equal_ignore_case, value) + elif numeric_condition := condition.get("numeric"): + return self._evaluate_numeric_condition(numeric_condition, value) + + elif cidr := condition.get("cidr"): + ips = [str(ip) for ip in ipaddress.IPv4Network(cidr)] + return value in ips + + elif wildcard := condition.get("wildcard"): + return self._evaluate_wildcard(wildcard, value) + + return False + + @staticmethod + def _evaluate_prefix(condition: str | list, value: str) -> bool: + return value.startswith(condition) + + @staticmethod + def _evaluate_suffix(condition: str | list, value: str) -> bool: + return value.endswith(condition) + + @staticmethod + def _evaluate_equal_ignore_case(condition: str, value: str) -> bool: + return condition.lower() == value.lower() + + @staticmethod + def _evaluate_wildcard(condition: str, value: str) -> bool: + return re.match(re.escape(condition).replace("\\*", ".+") + "$", value) + + @staticmethod + def _evaluate_numeric_condition(conditions, value) -> bool: + try: + # try if the value is numeric + value = float(value) + except ValueError: + # the value is not numeric, the condition is False + return False + + for i in range(0, len(conditions), 2): + operator = conditions[i] + operand = float(conditions[i + 1]) + + if operator == "=": + if value != operand: + return False + elif operator == ">": + if value <= operand: + return False + elif operator == "<": + if value >= operand: + return False + elif operator == ">=": + if value < operand: + return False + elif operator == "<=": + if value > operand: + return False + + return True + + @staticmethod + def flatten_pattern(nested_dict: dict) -> list[dict]: + """ + Takes a dictionary as input and will output the dictionary on a single level. + Input: + `{"field1": {"field2": {"field3": "val1", "field4": "val2"}}}` + Output: + `[ + { + "field1.field2.field3": "val1", + "field1.field2.field4": "val2" + } + ]` + Input with $or will create multiple outputs: + `{"$or": [{"field1": "val1"}, {"field2": "val2"}], "field3": "val3"}` + Output: + `[ + {"field1": "val1", "field3": "val3"}, + {"field2": "val2", "field3": "val3"} + ]` + :param nested_dict: a (nested) dictionary + :return: a list of flattened dictionaries with no nested dict or list inside, flattened to a + single level, one list item for every list item encountered + """ + + def _traverse_event_pattern(obj, array=None, parent_key=None) -> list: + if array is None: + array = [{}] + + for key, values in obj.items(): + if key == "$or" and isinstance(values, list) and len(values) > 1: + # $or will create multiple new branches in the array. + # Each current branch will traverse with each choice in $or + array = [ + i + for value in values + for i in _traverse_event_pattern(value, array, parent_key) + ] + else: + # We update the parent key do that {"key1": {"key2": ""}} becomes "key1.key2" + _parent_key = f"{parent_key}.{key}" if parent_key else key + if isinstance(values, dict): + # If the current key has child dict -- key: "key1", child: {"key2": ["val1", val2"]} + # We only update the parent_key and traverse its children with the current branches + array = _traverse_event_pattern(values, array, _parent_key) + else: + # If the current key has no child, this means we found the values to match -- child: ["val1", val2"] + # we update the branches with the parent chain and the values -- {"key1.key2": ["val1, val2"]} + array = [{**item, _parent_key: values} for item in array] + + return array + + return _traverse_event_pattern(nested_dict) + + @staticmethod + def flatten_payload(nested_dict: dict) -> list[dict]: + """ + Takes a dictionary as input and will output the dictionary on a single level. + The dictionary can have lists containing other dictionaries, and one root level entry will be created for every + item in a list. + Input: + `{"field1": { + "field2: [ + {"field3: "val1", "field4": "val2"}, + {"field3: "val3", "field4": "val4"}, + } + ]}` + Output: + `[ + { + "field1.field2.field3": "val1", + "field1.field2.field4": "val2" + }, + { + "field1.field2.field3": "val3", + "field1.field2.field4": "val4" + }, + ]` + :param nested_dict: a (nested) dictionary + :return: flatten_dict: a dictionary with no nested dict inside, flattened to a single level + """ + + def _traverse(_object: dict, array=None, parent_key=None) -> list: + if isinstance(_object, dict): + for key, values in _object.items(): + # We update the parent key do that {"key1": {"key2": ""}} becomes "key1.key2" + _parent_key = f"{parent_key}.{key}" if parent_key else key + array = _traverse(values, array, _parent_key) + + elif isinstance(_object, list): + if not _object: + return array + array = [i for value in _object for i in _traverse(value, array, parent_key)] + else: + array = [{**item, parent_key: _object} for item in array] + return array + + return _traverse(nested_dict, array=[{}], parent_key=None) + + +class EventPatternCompiler: + def __init__(self): + self.error_prefix = "Event pattern is not valid. Reason: " + + def compile_event_pattern(self, event_pattern: str | dict) -> dict[str, t.Any]: + if isinstance(event_pattern, str): + try: + event_pattern = json.loads(event_pattern) + if not isinstance(event_pattern, dict): + raise InvalidEventPatternException( + f"{self.error_prefix}Filter is not an object" + ) + except json.JSONDecodeError: + # this error message is not in parity, as it is tightly coupled to AWS parsing engine + raise InvalidEventPatternException(f"{self.error_prefix}Filter is not valid JSON") + + aggregated_rules, combinations = self.aggregate_rules(event_pattern) + + for rules in aggregated_rules: + for rule in rules: + self._validate_rule(rule) + + return event_pattern + + def aggregate_rules(self, event_pattern: dict[str, t.Any]) -> tuple[list[list[t.Any]], int]: + """ + This method evaluate the event pattern recursively, and returns only a list of lists of rules. + It also calculates the combinations of rules, calculated depending on the nesting of the rules. + Example: + nested_event_pattern = { + "key_a": { + "key_b": { + "key_c": ["value_one", "value_two", "value_three", "value_four"] + } + }, + "key_d": { + "key_e": ["value_one", "value_two", "value_three"] + } + } + This function then iterates on the values of the top level keys of the event pattern: ("key_a", "key_d") + If the iterated value is not a list, it means it is a nested property. If the scope is `MessageBody`, it is + allowed, we call this method on the value, adding a level to the depth to keep track on how deep the key is. + If the value is a list, it means it contains rules: we will append this list of rules in _rules, and + calculate the combinations it adds. + For the example event pattern containing nested properties, we calculate it this way + The first array has four values in a three-level nested key, and the second has three values in a two-level + nested key. 3 x 4 x 2 x 3 = 72 + The return value would be: + [["value_one", "value_two", "value_three", "value_four"], ["value_one", "value_two", "value_three"]] + It allows us to later iterate of the list of rules in an easy way, to verify its conditions only. + + :param event_pattern: a dict, starting at the Event Pattern + :return: a tuple with a list of lists of rules and the calculated number of combinations + """ + + def _inner( + pattern_elements: dict[str, t.Any], depth: int = 1, combinations: int = 1 + ) -> tuple[list[list[t.Any]], int]: + _rules = [] + for key, _value in pattern_elements.items(): + if isinstance(_value, dict): + # From AWS docs: "unlike attribute-based policies, payload-based policies support property nesting." + sub_rules, combinations = _inner( + _value, depth=depth + 1, combinations=combinations + ) + _rules.extend(sub_rules) + elif isinstance(_value, list): + if not _value: + raise InvalidEventPatternException( + f"{self.error_prefix}Empty arrays are not allowed" + ) + + current_combination = 0 + if key == "$or": + for val in _value: + sub_rules, or_combinations = _inner( + val, depth=depth, combinations=combinations + ) + _rules.extend(sub_rules) + current_combination += or_combinations + + combinations = current_combination + else: + _rules.append(_value) + combinations = combinations * len(_value) * depth + else: + raise InvalidEventPatternException( + f'{self.error_prefix}"{key}" must be an object or an array' + ) + + return _rules, combinations + + return _inner(event_pattern) + + def _validate_rule(self, rule: t.Any, from_: str | None = None) -> None: + match rule: + case None | str() | bool(): + return + + case int() | float(): + # TODO: AWS says they support only from -10^9 to 10^9 but seems to accept it, so we just return + # if rule <= -1000000000 or rule >= 1000000000: + # raise "" + return + + case {**kwargs}: + if len(kwargs) != 1: + raise InvalidEventPatternException( + f"{self.error_prefix}Only one key allowed in match expression" + ) + + operator, value = None, None + for k, v in kwargs.items(): + operator, value = k, v + + if operator in ( + "prefix", + "suffix", + ): + if from_ == "anything-but": + if isinstance(value, dict): + raise InvalidEventPatternException( + f"{self.error_prefix}Value of {from_} must be an array or single string/number value." + ) + + if not self._is_str_or_list_of_str(value): + raise InvalidEventPatternException( + f"{self.error_prefix}prefix/suffix match pattern must be a string" + ) + + elif isinstance(value, dict): + for inner_operator in value.keys(): + if inner_operator != "equals-ignore-case": + raise InvalidEventPatternException( + f"{self.error_prefix}Unsupported anything-but pattern: {inner_operator}" + ) + + elif not isinstance(value, str): + raise InvalidEventPatternException( + f"{self.error_prefix}{operator} match pattern must be a string" + ) + return + + elif operator == "equals-ignore-case": + if from_ == "anything-but": + if not self._is_str_or_list_of_str(value): + raise InvalidEventPatternException( + f"{self.error_prefix}Inside {from_}/{operator} list, number|start|null|boolean is not supported." + ) + elif not isinstance(value, str): + raise InvalidEventPatternException( + f"{self.error_prefix}{operator} match pattern must be a string" + ) + return + + elif operator == "anything-but": + # anything-but can actually contain any kind of simple rule (str, number, and list) + if isinstance(value, list): + for v in value: + self._validate_rule(v) + + return + + # or have a nested `prefix`, `suffix` or `equals-ignore-case` pattern + elif isinstance(value, dict): + for inner_operator in value.keys(): + if inner_operator not in ( + "prefix", + "equals-ignore-case", + "suffix", + "wildcard", + ): + raise InvalidEventPatternException( + f"{self.error_prefix}Unsupported anything-but pattern: {inner_operator}" + ) + + self._validate_rule(value, from_="anything-but") + return + + elif operator == "exists": + if not isinstance(value, bool): + raise InvalidEventPatternException( + f"{self.error_prefix}exists match pattern must be either true or false." + ) + return + + elif operator == "numeric": + self._validate_numeric_condition(value) + + elif operator == "cidr": + try: + ipaddress.IPv4Network(value) + except ValueError: + raise InvalidEventPatternException( + f"{self.error_prefix}Malformed CIDR, one '/' required" + ) + elif operator == "wildcard": + if from_ == "anything-but" and isinstance(value, list): + for v in value: + self._validate_wildcard(v) + else: + self._validate_wildcard(value) + + else: + raise InvalidEventPatternException( + f"{self.error_prefix}Unrecognized match type {operator}" + ) + + case _: + raise InvalidEventPatternException( + f"{self.error_prefix}Match value must be String, number, true, false, or null" + ) + + def _validate_numeric_condition(self, value): + if not value: + raise InvalidEventPatternException( + f"{self.error_prefix}Invalid member in numeric match: ]" + ) + num_values = value[::-1] + + operator = num_values.pop() + if not isinstance(operator, str): + raise InvalidEventPatternException( + f"{self.error_prefix}Invalid member in numeric match: {operator}" + ) + elif operator not in ("<", "<=", "=", ">", ">="): + raise InvalidEventPatternException( + f"{self.error_prefix}Unrecognized numeric range operator: {operator}" + ) + + value = num_values.pop() if num_values else None + if not isinstance(value, (int, float)): + exc_operator = "equals" if operator == "=" else operator + raise InvalidEventPatternException( + f"{self.error_prefix}Value of {exc_operator} must be numeric" + ) + + if not num_values: + return + + if operator not in (">", ">="): + raise InvalidEventPatternException( + f"{self.error_prefix}Too many elements in numeric expression" + ) + + second_operator = num_values.pop() + if not isinstance(second_operator, str): + raise InvalidEventPatternException( + f"{self.error_prefix}Bad value in numeric range: {second_operator}" + ) + elif second_operator not in ("<", "<="): + raise InvalidEventPatternException( + f"{self.error_prefix}Bad numeric range operator: {second_operator}" + ) + + second_value = num_values.pop() if num_values else None + if not isinstance(second_value, (int, float)): + exc_operator = "equals" if second_operator == "=" else second_operator + raise InvalidEventPatternException( + f"{self.error_prefix}Value of {exc_operator} must be numeric" + ) + + elif second_value <= value: + raise InvalidEventPatternException(f"{self.error_prefix}Bottom must be less than top") + + elif num_values: + raise InvalidEventPatternException( + f"{self.error_prefix}Too many terms in numeric range expression" + ) + + def _validate_wildcard(self, value: t.Any): + if not isinstance(value, str): + raise InvalidEventPatternException( + f"{self.error_prefix}wildcard match pattern must be a string" + ) + # TODO: properly calculate complexity of wildcard + # https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-pattern-operators.html#eb-filtering-wildcard-matching-complexity + # > calculate complexity of repeating character sequences that occur after a wildcard character + if "**" in value: + raise InvalidEventPatternException( + f"{self.error_prefix}Consecutive wildcard characters at pos {value.index('**') + 1}" + ) + + if value.count("*") > 5: + raise InvalidEventPatternException( + f"{self.error_prefix}Rule is too complex - try using fewer wildcard characters or fewer repeating character sequences after a wildcard character" + ) + + @staticmethod + def _is_str_or_list_of_str(value: t.Any) -> bool: + if not isinstance(value, (str, list)): + return False + if isinstance(value, list) and not all(isinstance(v, str) for v in value): + return False + + return True diff --git a/localstack-core/localstack/services/events/event_ruler.py b/localstack-core/localstack/services/events/event_ruler.py index ea0ab15107fb9..fd1a825f5b60a 100644 --- a/localstack-core/localstack/services/events/event_ruler.py +++ b/localstack-core/localstack/services/events/event_ruler.py @@ -4,7 +4,7 @@ from pathlib import Path from typing import Tuple -from localstack.services.events.models import InvalidEventPatternException +from localstack.aws.api.events import InvalidEventPatternException from localstack.services.events.packages import event_ruler_package from localstack.utils.objects import singleton_factory @@ -66,4 +66,6 @@ def matches_rule(event: str, rule: str) -> bool: return Ruler.matchesRule(event, rule) except java.lang.Exception as e: reason = e.args[0] - raise InvalidEventPatternException(reason=reason) from e + raise InvalidEventPatternException( + message=f"Event pattern is not valid. Reason: {reason}" + ) from e diff --git a/localstack-core/localstack/services/events/provider.py b/localstack-core/localstack/services/events/provider.py index 16923f2d5e03d..8dc1ca11d47e5 100644 --- a/localstack-core/localstack/services/events/provider.py +++ b/localstack-core/localstack/services/events/provider.py @@ -53,7 +53,6 @@ EventSourceName, HttpsEndpoint, InternalException, - InvalidEventPatternException, KmsKeyIdentifier, LimitMax100, ListApiDestinationsResponse, @@ -134,9 +133,6 @@ ValidationException, events_stores, ) -from localstack.services.events.models import ( - InvalidEventPatternException as InternalInvalidEventPatternException, -) from localstack.services.events.replay import ReplayService, ReplayServiceDict from localstack.services.events.rule import RuleService, RuleServiceDict from localstack.services.events.scheduler import JobScheduler @@ -155,7 +151,6 @@ get_trace_header_encoded_region_account, is_archive_arn, recursive_remove_none_values_from_dict, - to_json_str, ) from localstack.services.plugins import ServiceLifecycleHook from localstack.utils.aws.arns import get_partition, parse_arn @@ -1212,11 +1207,7 @@ def test_event_pattern( """Test event pattern uses EventBridge event pattern matching: https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns.html """ - try: - result = matches_event(event_pattern, event) - except InternalInvalidEventPatternException as e: - raise InvalidEventPatternException(e.message) from e - + result = matches_event(event_pattern, event) return TestEventPatternResponse(Result=result) ######### @@ -2137,8 +2128,8 @@ def _process_rules( ) -> None: """Process rules for an event. Note that we no longer handle entries here as AWS returns success regardless of target failures.""" event_pattern = rule.event_pattern - event_str = to_json_str(event_formatted) - if matches_event(event_pattern, event_str): + + if matches_event(event_pattern, event_formatted): if not rule.targets: LOG.info( json.dumps( diff --git a/localstack-core/localstack/services/events/v1/utils.py b/localstack-core/localstack/services/events/v1/utils.py index 9fdd1550d93c5..38746dca1735b 100644 --- a/localstack-core/localstack/services/events/v1/utils.py +++ b/localstack-core/localstack/services/events/v1/utils.py @@ -4,9 +4,10 @@ import re from typing import Any -from localstack.services.events.models import InvalidEventPatternException +from localstack.aws.api.events import InvalidEventPatternException CONTENT_BASE_FILTER_KEYWORDS = ["prefix", "anything-but", "numeric", "cidr", "exists"] +_error_prefix = "Event pattern is not valid. Reason: " LOG = logging.getLogger(__name__) @@ -245,11 +246,11 @@ def handle_numeric_conditions(conditions: list[any], value: int | float): # Invalid example for uneven list: { "numeric": [ ">", 0, "<" ] } if len(conditions) % 2 > 0: - raise InvalidEventPatternException("Bad numeric range operator") + raise InvalidEventPatternException(f"{_error_prefix}Bad numeric range operator") if not isinstance(value, (int, float)): raise InvalidEventPatternException( - f"The value {value} for the numeric comparison {conditions} is not a valid number" + f"{_error_prefix}The value {value} for the numeric comparison {conditions} is not a valid number" ) for i in range(0, len(conditions), 2): @@ -259,7 +260,7 @@ def handle_numeric_conditions(conditions: list[any], value: int | float): second_operand = float(second_operand_str) except ValueError: raise InvalidEventPatternException( - f"Could not convert filter value {second_operand_str} to a valid number" + f"{_error_prefix}Could not convert filter value {second_operand_str} to a valid number" ) if operator == "<" and not (value < second_operand): diff --git a/localstack-core/localstack/utils/event_matcher.py b/localstack-core/localstack/utils/event_matcher.py index 69bb39cac0b77..157766bd11f15 100644 --- a/localstack-core/localstack/utils/event_matcher.py +++ b/localstack-core/localstack/utils/event_matcher.py @@ -2,8 +2,11 @@ from typing import Any from localstack import config +from localstack.services.events.event_rule_engine import EventPatternCompiler, EventRuleEngine from localstack.services.events.event_ruler import matches_rule -from localstack.services.events.v1.utils import matches_event as python_matches_event + +_event_pattern_compiler = EventPatternCompiler() +_event_rule_engine = EventRuleEngine() def matches_event(event_pattern: dict[str, Any] | str | None, event: dict[str, Any] | str) -> bool: @@ -48,7 +51,10 @@ def matches_event(event_pattern: dict[str, Any] | str | None, event: dict[str, A return matches_rule(event_str, pattern_str) # Python implementation (default) - # Convert strings to dicts if necessary - event_dict = json.loads(event) if isinstance(event, str) else event - pattern_dict = json.loads(event_pattern) if isinstance(event_pattern, str) else event_pattern - return python_matches_event(pattern_dict, event_dict) + compiled_event_pattern = _event_pattern_compiler.compile_event_pattern( + event_pattern=event_pattern + ) + return _event_rule_engine.evaluate_pattern_on_event( + compiled_event_pattern=compiled_event_pattern, + event=event, + ) diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_EXC.json5 new file mode 100644 index 0000000000000..68ca8d92e5f81 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_EXC.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": "pending" + } + }, + "EventPattern": { + "detail": { + "state" : [{ "anything-but": { "equals-ignore-case": 123 }}] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_list_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_list_EXC.json5 new file mode 100644 index 0000000000000..0b7f4f8bdf067 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_list_EXC.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": "pending" + } + }, + "EventPattern": { + "detail": { + "state" : [{ "anything-but": { "equals-ignore-case": [123, 456] }}] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_but_string_null.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_but_string_null.json5 new file mode 100644 index 0000000000000..c0f437399730e --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_but_string_null.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": null + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": "initializing" } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_prefix_ignorecase_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_ignorecase_EXC.json5 new file mode 100644 index 0000000000000..3233ae6b05e79 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_ignorecase_EXC.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "FileName": "file.txt.bak" + } + }, + "EventPattern": { + "detail": { + "FileName": [ { "anything-but": { "prefix": { "equals-ignore-case": "file" }} } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_prefix_int_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_int_EXC.json5 new file mode 100644 index 0000000000000..9e0fb60ec6de3 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_int_EXC.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": "post-init" + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": { "prefix": 123 } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list.json5 new file mode 100644 index 0000000000000..57465d83b1305 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": "post-init" + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": { "prefix": ["init", "test"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_NEG.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_NEG.json5 new file mode 100644 index 0000000000000..4a7a91a66dc90 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_NEG.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": "post-init" + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": { "prefix": ["init", "post"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_type_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_type_EXC.json5 new file mode 100644 index 0000000000000..a1a43c6dd1ff0 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_type_EXC.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": "post-init" + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": { "prefix": [123, "test"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_suffix_ignorecase_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_ignorecase_EXC.json5 new file mode 100644 index 0000000000000..87a47bb65375f --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_ignorecase_EXC.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "FileName": "file.txt.bak" + } + }, + "EventPattern": { + "detail": { + "FileName": [ { "anything-but": { "suffix": { "equals-ignore-case": ".png" }} } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_suffix_int_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_int_EXC.json5 new file mode 100644 index 0000000000000..5fcb5ae223d1d --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_int_EXC.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "FileName": "file.txt.bak" + } + }, + "EventPattern": { + "detail": { + "FileName": [ { "anything-but": { "suffix": 123 } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list.json5 new file mode 100644 index 0000000000000..2e89c74c408ac --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "FileName": "file.txt.bak" + } + }, + "EventPattern": { + "detail": { + "FileName": [ { "anything-but": { "suffix": [".txt", ".jpg"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_NEG.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_NEG.json5 new file mode 100644 index 0000000000000..9e7edb0b0a64a --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_NEG.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "FileName": "file.jpg" + } + }, + "EventPattern": { + "detail": { + "FileName": [ { "anything-but": { "suffix": [".txt", ".jpg"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_type_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_type_EXC.json5 new file mode 100644 index 0000000000000..61308b55cd2a1 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_type_EXC.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "FileName": "file.txt.bak" + } + }, + "EventPattern": { + "detail": { + "FileName": [ { "anything-but": { "suffix": [123, ".txt"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_wildcard.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard.json5 new file mode 100644 index 0000000000000..32c3b12af8a71 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "FilePath": "dir/init/file" + } + }, + "EventPattern": { + "detail": { + "FilePath": [ { "anything-but": { "wildcard": "*/dir/*" } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_NEG.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_NEG.json5 new file mode 100644 index 0000000000000..7bf54079df002 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_NEG.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "FilePath": "dir/init/file" + } + }, + "EventPattern": { + "detail": { + "FilePath": [ { "anything-but": { "wildcard": "*/init/*" } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list.json5 new file mode 100644 index 0000000000000..1fe576b0208b6 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": "dir/post/dir" + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": { "wildcard": ["*/init/*", "*/dir/*"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list_NEG.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list_NEG.json5 new file mode 100644 index 0000000000000..86af67b3c7ad0 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list_NEG.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": "dir/init/dir" + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": { "wildcard": ["*/init/*", "*/dir/*"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list_type_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list_type_EXC.json5 new file mode 100644 index 0000000000000..5af83d01e4370 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list_type_EXC.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": "dir/post/dir" + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": { "wildcard": [123, "*/dir/*"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_type_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_type_EXC.json5 new file mode 100644 index 0000000000000..ee855a4ecc0a5 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_type_EXC.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "FilePath": "dir/init/file" + } + }, + "EventPattern": { + "detail": { + "FilePath": [ { "anything-but": { "wildcard": 123 } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_ignorecase_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_ignorecase_EXC.json5 new file mode 100644 index 0000000000000..0d45f3eb541f1 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_ignorecase_EXC.json5 @@ -0,0 +1,14 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-equals-ignore-case-matching +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": [ "EC2 Instance State-change Notification" ], + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + }, + "EventPattern": { + "detail-type": [ { "equals-ignore-case": ["ec2 instance state-change notification"] } ] + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_ignorecase_list_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_ignorecase_list_EXC.json5 new file mode 100644 index 0000000000000..826fbab8a0c0f --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_ignorecase_list_EXC.json5 @@ -0,0 +1,14 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-equals-ignore-case-matching +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": [ "EC2 Instance State-change Notification" ], + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + }, + "EventPattern": { + "detail-type": [ { "equals-ignore-case": {"prefix": "ec2"} } ] + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_ip_address_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_ip_address_EXC.json5 new file mode 100644 index 0000000000000..f199a531c267e --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_ip_address_EXC.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-ip-matching +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "sourceIPAddress": "10.0.0.255" + } + }, + "EventPattern": { + "detail": { + "sourceIPAddress": [ { "cidr": "bad-filter" } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_prefix_int_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_prefix_int_EXC.json5 new file mode 100644 index 0000000000000..e2b030b5527ed --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_prefix_int_EXC.json5 @@ -0,0 +1,14 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-prefix-matching +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + }, + "EventPattern": { + "time": [ { "prefix": 123 } ] + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_prefix_list_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_prefix_list_EXC.json5 new file mode 100644 index 0000000000000..2182689cec58d --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_prefix_list_EXC.json5 @@ -0,0 +1,14 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-prefix-matching +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + }, + "EventPattern": { + "time": [ { "prefix": ["2022-07-13"] } ] + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_suffix_int_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_suffix_int_EXC.json5 new file mode 100644 index 0000000000000..0e5e862d00d7e --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_suffix_int_EXC.json5 @@ -0,0 +1,15 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-suffix-matching +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "FileName": "image.png" + }, + "EventPattern": { + "FileName": [ { "suffix": 123 } ] + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_suffix_list_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_suffix_list_EXC.json5 new file mode 100644 index 0000000000000..4cc9933bb06f9 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_suffix_list_EXC.json5 @@ -0,0 +1,15 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-suffix-matching +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "FileName": "image.png" + }, + "EventPattern": { + "FileName": [ { "suffix": [".png"] } ] + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_wildcard_int_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_wildcard_int_EXC.json5 new file mode 100644 index 0000000000000..f000e40c7157d --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_wildcard_int_EXC.json5 @@ -0,0 +1,15 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-wildcard-matching +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "EventBusArn": "arn:aws:events:us-east-1:123456789012:event-bus/myEventBus" + }, + "EventPattern": { + "EventBusArn": [ { "wildcard": 123 } ] + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_wildcard_list_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_wildcard_list_EXC.json5 new file mode 100644 index 0000000000000..c9531b4ea8b92 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_wildcard_list_EXC.json5 @@ -0,0 +1,15 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-wildcard-matching +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "EventBusArn": "arn:aws:events:us-east-1:123456789012:event-bus/myEventBus" + }, + "EventPattern": { + "EventBusArn": [ { "wildcard": ["arn:aws:events:us-east-1:**:event-bus/*"] } ] + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_wildcard_repeating_star_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_wildcard_repeating_star_EXC.json5 new file mode 100644 index 0000000000000..411658e590530 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_wildcard_repeating_star_EXC.json5 @@ -0,0 +1,15 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-wildcard-matching +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "EventBusArn": "arn:aws:events:us-east-1:123456789012:event-bus/myEventBus" + }, + "EventPattern": { + "EventBusArn": [ { "wildcard": "arn:aws:events:us-east-1:**:event-bus/*" } ] + } +} diff --git a/tests/aws/services/events/test_events_patterns.py b/tests/aws/services/events/test_events_patterns.py index 1322c029b30ba..916a2069fb59b 100644 --- a/tests/aws/services/events/test_events_patterns.py +++ b/tests/aws/services/events/test_events_patterns.py @@ -1,3 +1,4 @@ +import copy import json import os from datetime import datetime @@ -6,8 +7,8 @@ import json5 import pytest +from botocore.exceptions import ClientError -from localstack.testing.aws.util import is_aws_cloud from localstack.testing.pytest import markers from localstack.utils.common import short_uid from tests.aws.services.events.helper_functions import ( @@ -21,40 +22,6 @@ ) COMPLEX_MULTI_KEY_EVENT = os.path.join(REQUEST_TEMPLATE_DIR, "complex_multi_key_event.json") -SKIP_LABELS = [ - # TODO: fix failing exception tests (not yet implemented) - "arrays_empty_EXC", - "content_numeric_EXC", - "content_numeric_operatorcasing_EXC", - "content_numeric_syntax_EXC", - "content_wildcard_complex_EXC", - "int_nolist_EXC", - "operator_case_sensitive_EXC", - "string_nolist_EXC", - # TODO: fix failing tests for Python event rule engine - "complex_or", - "content_anything_but_ignorecase", - "content_anything_but_ignorecase_list", - "content_anything_suffix", - "content_exists_false", - "content_ignorecase", - "content_ignorecase_NEG", - "content_ip_address", - "content_numeric_and", - "content_prefix_ignorecase", - "content_suffix", - "content_suffix_ignorecase", - "content_wildcard_nonrepeating", - "content_wildcard_repeating", - "content_wildcard_simplified", - "dot_joining_event", - "dot_joining_pattern", - "exists_dynamodb_NEG", - "nested_json_NEG", - "or-exists", - "or-exists-parent", -] - def load_request_templates(directory_path: str) -> List[Tuple[dict, str]]: json5_files = list_files_with_suffix(directory_path, ".json5") @@ -91,27 +58,38 @@ class TestEventPattern: ids=[t[1] for t in request_template_tuples], ) @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=["$..MessageRaw"], # AWS returns Java validation parts, we skip those + ) def test_event_pattern(self, aws_client, snapshot, request_template, label): """This parametrized test handles three outcomes: a) MATCH (default): The EventPattern matches the Event yielding true as result. b) NO MATCH (_NEG suffix): The EventPattern does NOT match the Event yielding false as result. c) EXCEPTION (_EXC suffix): The EventPattern is invalid and raises an exception. """ - if label in SKIP_LABELS and not is_aws_cloud(): - pytest.skip("Not yet implemented") + + def _transform_raw_exc_message( + boto_error: dict[str, dict[str, str]], + ) -> dict[str, dict[str, str]]: + if message := boto_error.get("Error", {}).get("Message"): + boto_error = copy.deepcopy(boto_error) + boto_error["Error"]["MessageRaw"] = message + boto_error["Error"]["Message"] = message.split("\n")[0] + + return boto_error event = request_template["Event"] event_pattern = request_template["EventPattern"] if label.endswith("_EXC"): - with pytest.raises(Exception) as e: + with pytest.raises(ClientError) as e: aws_client.events.test_event_pattern( Event=json.dumps(event), EventPattern=json.dumps(event_pattern), ) exception_info = { "exception_type": type(e.value), - "exception_message": e.value.response, + "exception_message": _transform_raw_exc_message(e.value.response), } snapshot.match(label, exception_info) else: @@ -120,7 +98,8 @@ def test_event_pattern(self, aws_client, snapshot, request_template, label): EventPattern=json.dumps(event_pattern), ) - # Validate the test intention: The _NEG suffix indicates negative tests (i.e., a pattern not matching the event) + # Validate the test intention: The _NEG suffix indicates negative tests + # (i.e., a pattern not matching the event) if label.endswith("_NEG"): assert not response["Result"] else: @@ -209,6 +188,30 @@ def test_event_pattern_source(self, aws_client, snapshot, account_id, region_nam ) snapshot.match("eventbridge-test-event-pattern-response-no-match", response) + @markers.aws.validated + @pytest.mark.parametrize( + "pattern", + [ + "this is valid json but not a dict", + "{'bad': 'quotation'}", + '{"not": closed mark"', + '["not", "a", "dict", "but valid json"]', + ], + ) + @markers.snapshot.skip_snapshot_verify( + # we cannot really validate the message, it is strongly coupled to AWS parsing engine + paths=["$..Error.Message"], + ) + def test_invalid_json_event_pattern(self, aws_client, pattern, snapshot): + event = '{"id": "1", "source": "test-source", "detail-type": "test-detail-type", "account": "123456789012", "region": "us-east-2", "time": "2022-07-13T13:48:01Z", "detail": {"test": "test"}}' + + with pytest.raises(ClientError) as e: + aws_client.events.test_event_pattern( + Event=event, + EventPattern=pattern, + ) + snapshot.match("invalid-pattern", e.value.response) + class TestRuleWithPattern: @markers.aws.validated diff --git a/tests/aws/services/events/test_events_patterns.snapshot.json b/tests/aws/services/events/test_events_patterns.snapshot.json index 3b80fc34da2cb..f79774848ab49 100644 --- a/tests/aws/services/events/test_events_patterns.snapshot.json +++ b/tests/aws/services/events/test_events_patterns.snapshot.json @@ -1,28 +1,29 @@ { "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating]": { - "recorded-date": "11-07-2024, 13:55:25", + "recorded-date": "29-11-2024, 01:41:23", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[list_within_dict]": { - "recorded-date": "11-07-2024, 13:55:25", + "recorded-date": "29-11-2024, 01:41:23", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_NEG]": { - "recorded-date": "11-07-2024, 13:55:25", + "recorded-date": "29-11-2024, 01:41:24", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_multi_match]": { - "recorded-date": "11-07-2024, 13:55:25", + "recorded-date": "29-11-2024, 01:41:24", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[int_nolist_EXC]": { - "recorded-date": "11-07-2024, 13:55:25", + "recorded-date": "29-11-2024, 01:41:24", "recorded-content": { "int_nolist_EXC": { "exception_message": { "Error": { "Code": "InvalidEventPatternException", - "Message": "Event pattern is not valid. Reason: \"int\" must be an object or an array\n at [Source: (String)\"{\"int\": 42}\"; line: 1, column: 11]" + "Message": "Event pattern is not valid. Reason: \"int\" must be an object or an array", + "MessageRaw": "Event pattern is not valid. Reason: \"int\" must be an object or an array\n at [Source: (String)\"{\"int\": 42}\"; line: 1, column: 11]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -34,45 +35,46 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays]": { - "recorded-date": "11-07-2024, 13:55:26", + "recorded-date": "29-11-2024, 01:41:25", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating_NEG]": { - "recorded-date": "11-07-2024, 13:55:26", + "recorded-date": "29-11-2024, 01:41:25", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_NEG]": { - "recorded-date": "11-07-2024, 13:55:26", + "recorded-date": "29-11-2024, 01:41:25", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_simplified]": { - "recorded-date": "11-07-2024, 13:55:26", + "recorded-date": "29-11-2024, 01:41:26", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-exists]": { - "recorded-date": "11-07-2024, 13:55:26", + "recorded-date": "29-11-2024, 01:41:26", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_nonrepeating]": { - "recorded-date": "11-07-2024, 13:55:26", + "recorded-date": "29-11-2024, 01:41:26", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_multi_match_NEG]": { - "recorded-date": "11-07-2024, 13:55:27", + "recorded-date": "29-11-2024, 01:41:27", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string]": { - "recorded-date": "11-07-2024, 13:55:27", + "recorded-date": "29-11-2024, 01:41:27", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_operatorcasing_EXC]": { - "recorded-date": "11-07-2024, 13:55:27", + "recorded-date": "29-11-2024, 01:41:27", "recorded-content": { "content_numeric_operatorcasing_EXC": { "exception_message": { "Error": { "Code": "InvalidEventPatternException", - "Message": "Event pattern is not valid. Reason: Unrecognized match type NUMERIC\n at [Source: (String)\"{\"detail\": {\"equal\": [{\"NUMERIC\": [\"=\", 5]}]}}\"; line: 1, column: 36]" + "Message": "Event pattern is not valid. Reason: Unrecognized match type NUMERIC", + "MessageRaw": "Event pattern is not valid. Reason: Unrecognized match type NUMERIC\n at [Source: (String)\"{\"detail\": {\"equal\": [{\"NUMERIC\": [\"=\", 5]}]}}\"; line: 1, column: 36]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -84,25 +86,26 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_list_NEG]": { - "recorded-date": "11-07-2024, 13:55:27", + "recorded-date": "29-11-2024, 01:41:28", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address]": { - "recorded-date": "11-07-2024, 13:55:28", + "recorded-date": "29-11-2024, 01:41:28", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_NEG]": { - "recorded-date": "11-07-2024, 13:55:28", + "recorded-date": "29-11-2024, 01:41:28", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string_nolist_EXC]": { - "recorded-date": "11-07-2024, 13:55:28", + "recorded-date": "29-11-2024, 01:41:29", "recorded-content": { "string_nolist_EXC": { "exception_message": { "Error": { "Code": "InvalidEventPatternException", - "Message": "Event pattern is not valid. Reason: \"string\" must be an object or an array\n at [Source: (String)\"{\"string\": \"my-value\"}\"; line: 1, column: 13]" + "Message": "Event pattern is not valid. Reason: \"string\" must be an object or an array", + "MessageRaw": "Event pattern is not valid. Reason: \"string\" must be an object or an array\n at [Source: (String)\"{\"string\": \"my-value\"}\"; line: 1, column: 13]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -114,33 +117,34 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_dynamodb_NEG]": { - "recorded-date": "11-07-2024, 13:55:28", + "recorded-date": "29-11-2024, 01:41:29", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_NEG]": { - "recorded-date": "11-07-2024, 13:55:28", + "recorded-date": "29-11-2024, 01:41:29", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[boolean_NEG]": { - "recorded-date": "11-07-2024, 13:55:29", + "recorded-date": "29-11-2024, 01:41:29", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_dynamodb]": { - "recorded-date": "11-07-2024, 13:55:29", + "recorded-date": "29-11-2024, 01:41:29", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-exists-parent]": { - "recorded-date": "11-07-2024, 13:55:29", + "recorded-date": "29-11-2024, 01:41:29", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_empty_EXC]": { - "recorded-date": "11-07-2024, 13:55:29", + "recorded-date": "29-11-2024, 01:41:29", "recorded-content": { "arrays_empty_EXC": { "exception_message": { "Error": { "Code": "InvalidEventPatternException", - "Message": "Event pattern is not valid. Reason: Empty arrays are not allowed\n at [Source: (String)\"{\"resources\": []}\"; line: 1, column: 17]" + "Message": "Event pattern is not valid. Reason: Empty arrays are not allowed", + "MessageRaw": "Event pattern is not valid. Reason: Empty arrays are not allowed\n at [Source: (String)\"{\"resources\": []}\"; line: 1, column: 17]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -152,61 +156,62 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[nested_json_NEG]": { - "recorded-date": "11-07-2024, 13:55:29", + "recorded-date": "29-11-2024, 01:41:30", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_pattern]": { - "recorded-date": "11-07-2024, 13:55:30", + "recorded-date": "29-11-2024, 01:41:30", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[operator_multiple_list]": { - "recorded-date": "11-07-2024, 13:55:30", + "recorded-date": "29-11-2024, 01:41:30", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list]": { - "recorded-date": "11-07-2024, 13:55:30", + "recorded-date": "29-11-2024, 01:41:30", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dynamodb]": { - "recorded-date": "11-07-2024, 13:55:30", + "recorded-date": "29-11-2024, 01:41:30", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase]": { - "recorded-date": "11-07-2024, 13:55:30", + "recorded-date": "29-11-2024, 01:41:30", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string_empty]": { - "recorded-date": "11-07-2024, 13:55:30", + "recorded-date": "29-11-2024, 01:41:30", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_many_rules]": { - "recorded-date": "11-07-2024, 13:55:30", + "recorded-date": "29-11-2024, 01:41:31", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[null_value]": { - "recorded-date": "11-07-2024, 13:55:30", + "recorded-date": "29-11-2024, 01:41:31", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_list]": { - "recorded-date": "11-07-2024, 13:55:31", + "recorded-date": "29-11-2024, 01:41:31", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_nonrepeating_NEG]": { - "recorded-date": "11-07-2024, 13:55:31", + "recorded-date": "29-11-2024, 01:41:32", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_NEG]": { - "recorded-date": "11-07-2024, 13:55:31", + "recorded-date": "29-11-2024, 01:41:32", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[operator_case_sensitive_EXC]": { - "recorded-date": "11-07-2024, 13:55:31", + "recorded-date": "29-11-2024, 01:41:32", "recorded-content": { "operator_case_sensitive_EXC": { "exception_message": { "Error": { "Code": "InvalidEventPatternException", - "Message": "Event pattern is not valid. Reason: Unrecognized match type EXISTS\n at [Source: (String)\"{\"my_key\": [{\"EXISTS\": true}]}\"; line: 1, column: 28]" + "Message": "Event pattern is not valid. Reason: Unrecognized match type EXISTS", + "MessageRaw": "Event pattern is not valid. Reason: Unrecognized match type EXISTS\n at [Source: (String)\"{\"my_key\": [{\"EXISTS\": true}]}\"; line: 1, column: 28]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -218,21 +223,22 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists]": { - "recorded-date": "11-07-2024, 13:55:31", + "recorded-date": "29-11-2024, 01:41:33", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_NEG]": { - "recorded-date": "11-07-2024, 13:55:32", + "recorded-date": "29-11-2024, 01:41:33", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_EXC]": { - "recorded-date": "11-07-2024, 13:55:32", + "recorded-date": "29-11-2024, 01:41:33", "recorded-content": { "content_numeric_EXC": { "exception_message": { "Error": { "Code": "InvalidEventPatternException", - "Message": "Event pattern is not valid. Reason: Bad numeric range operator: >\n at [Source: (String)\"{\"detail\": {\"c-count\": [{\"numeric\": [\">\", 0, \">\", 0]}]}}\"; line: 1, column: 49]" + "Message": "Event pattern is not valid. Reason: Bad numeric range operator: >", + "MessageRaw": "Event pattern is not valid. Reason: Bad numeric range operator: >\n at [Source: (String)\"{\"detail\": {\"c-count\": [{\"numeric\": [\">\", 0, \">\", 0]}]}}\"; line: 1, column: 49]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -244,93 +250,94 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_or_NEG]": { - "recorded-date": "11-07-2024, 13:55:32", + "recorded-date": "29-11-2024, 01:41:34", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_or]": { - "recorded-date": "11-07-2024, 13:55:32", + "recorded-date": "29-11-2024, 01:41:34", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_and_NEG]": { - "recorded-date": "11-07-2024, 13:55:33", + "recorded-date": "29-11-2024, 01:41:34", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_event]": { - "recorded-date": "11-07-2024, 13:55:33", + "recorded-date": "29-11-2024, 01:41:34", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_NEG]": { - "recorded-date": "11-07-2024, 13:55:33", + "recorded-date": "29-11-2024, 01:41:35", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_ignorecase]": { - "recorded-date": "11-07-2024, 13:55:33", + "recorded-date": "29-11-2024, 01:41:35", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_ignorecase]": { - "recorded-date": "11-07-2024, 13:55:33", + "recorded-date": "29-11-2024, 01:41:35", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[null_value_NEG]": { - "recorded-date": "11-07-2024, 13:55:33", + "recorded-date": "29-11-2024, 01:41:35", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_pattern_NEG]": { - "recorded-date": "11-07-2024, 13:55:33", + "recorded-date": "29-11-2024, 01:41:35", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix]": { - "recorded-date": "11-07-2024, 13:55:33", + "recorded-date": "29-11-2024, 01:41:35", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[sample1]": { - "recorded-date": "11-07-2024, 13:55:34", + "recorded-date": "29-11-2024, 01:41:35", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[key_case_sensitive_NEG]": { - "recorded-date": "11-07-2024, 13:55:34", + "recorded-date": "29-11-2024, 01:41:35", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_event_NEG]": { - "recorded-date": "11-07-2024, 13:55:34", + "recorded-date": "29-11-2024, 01:41:36", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[prefix]": { - "recorded-date": "11-07-2024, 13:55:34", + "recorded-date": "29-11-2024, 01:41:36", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix]": { - "recorded-date": "11-07-2024, 13:55:34", + "recorded-date": "29-11-2024, 01:41:36", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list]": { - "recorded-date": "11-07-2024, 13:55:34", + "recorded-date": "29-11-2024, 01:41:36", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_NEG]": { - "recorded-date": "11-07-2024, 13:55:34", + "recorded-date": "29-11-2024, 01:41:36", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string]": { - "recorded-date": "11-07-2024, 13:55:34", + "recorded-date": "29-11-2024, 01:41:37", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_empty_null_NEG]": { - "recorded-date": "11-07-2024, 13:55:35", + "recorded-date": "29-11-2024, 01:41:37", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_ignorecase_NEG]": { - "recorded-date": "11-07-2024, 13:55:35", + "recorded-date": "29-11-2024, 01:41:37", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_complex_EXC]": { - "recorded-date": "11-07-2024, 13:55:35", + "recorded-date": "29-11-2024, 01:41:38", "recorded-content": { "content_wildcard_complex_EXC": { "exception_message": { "Error": { "Code": "InvalidEventPatternException", - "Message": "Event pattern is not valid. Reason: Rule is too complex - try using fewer wildcard characters or fewer repeating character sequences after a wildcard character" + "Message": "Event pattern is not valid. Reason: Rule is too complex - try using fewer wildcard characters or fewer repeating character sequences after a wildcard character", + "MessageRaw": "Event pattern is not valid. Reason: Rule is too complex - try using fewer wildcard characters or fewer repeating character sequences after a wildcard character" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -342,61 +349,62 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list_NEG]": { - "recorded-date": "11-07-2024, 13:55:35", + "recorded-date": "29-11-2024, 01:41:39", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix]": { - "recorded-date": "11-07-2024, 13:55:36", + "recorded-date": "29-11-2024, 01:41:40", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_NEG]": { - "recorded-date": "11-07-2024, 13:55:36", + "recorded-date": "29-11-2024, 01:41:40", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[minimal]": { - "recorded-date": "11-07-2024, 13:55:36", + "recorded-date": "29-11-2024, 01:41:40", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_false]": { - "recorded-date": "11-07-2024, 13:55:36", + "recorded-date": "29-11-2024, 01:41:41", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[number_comparison_float]": { - "recorded-date": "11-07-2024, 13:55:36", + "recorded-date": "29-11-2024, 01:41:42", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_NEG]": { - "recorded-date": "11-07-2024, 13:55:36", + "recorded-date": "29-11-2024, 01:41:42", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix]": { - "recorded-date": "11-07-2024, 13:55:36", + "recorded-date": "29-11-2024, 01:41:42", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_NEG]": { - "recorded-date": "11-07-2024, 13:55:36", + "recorded-date": "29-11-2024, 01:41:43", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase]": { - "recorded-date": "11-07-2024, 13:55:37", + "recorded-date": "29-11-2024, 01:41:43", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_false_NEG]": { - "recorded-date": "11-07-2024, 13:55:37", + "recorded-date": "29-11-2024, 01:41:43", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_NEG]": { - "recorded-date": "11-07-2024, 13:55:37", + "recorded-date": "29-11-2024, 01:41:43", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_syntax_EXC]": { - "recorded-date": "11-07-2024, 13:55:37", + "recorded-date": "29-11-2024, 01:41:43", "recorded-content": { "content_numeric_syntax_EXC": { "exception_message": { "Error": { "Code": "InvalidEventPatternException", - "Message": "Event pattern is not valid. Reason: Value of < must be numeric\n at [Source: (String)\"{\"detail\": {\"c-count\": [{\"numeric\": [\">\", 0, \"<\"]}]}}\"; line: 1, column: 50]" + "Message": "Event pattern is not valid. Reason: Value of < must be numeric", + "MessageRaw": "Event pattern is not valid. Reason: Value of < must be numeric\n at [Source: (String)\"{\"detail\": {\"c-count\": [{\"numeric\": [\">\", 0, \"<\"]}]}}\"; line: 1, column: 50]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -408,19 +416,19 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_and]": { - "recorded-date": "11-07-2024, 13:55:38", + "recorded-date": "29-11-2024, 01:41:44", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[boolean]": { - "recorded-date": "11-07-2024, 13:55:38", + "recorded-date": "29-11-2024, 01:41:44", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number]": { - "recorded-date": "11-07-2024, 13:55:38", + "recorded-date": "29-11-2024, 01:41:44", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-anything-but]": { - "recorded-date": "11-07-2024, 13:55:38", + "recorded-date": "29-11-2024, 01:41:44", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern_source": { @@ -570,5 +578,481 @@ } ] } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating_star_EXC]": { + "recorded-date": "29-11-2024, 01:41:26", + "recorded-content": { + "content_wildcard_repeating_star_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: Consecutive wildcard characters at pos 26", + "MessageRaw": "Event pattern is not valid. Reason: Consecutive wildcard characters at pos 26\n at [Source: (String)\"{\"EventBusArn\": [{\"wildcard\": \"arn::events::**:event-bus/*\"}]}\"; line: 1, column: 72]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_EXC]": { + "recorded-date": "29-11-2024, 01:41:31", + "recorded-content": { + "content_ignorecase_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: equals-ignore-case match pattern must be a string", + "MessageRaw": "Event pattern is not valid. Reason: equals-ignore-case match pattern must be a string\n at [Source: (String)\"{\"detail-type\": [{\"equals-ignore-case\": [\"ec2 instance state-change notification\"]}]}\"; line: 1, column: 42]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_EXC]": { + "recorded-date": "29-11-2024, 01:41:41", + "recorded-content": { + "content_ip_address_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: Malformed CIDR, one '/' required", + "MessageRaw": "Event pattern is not valid. Reason: Malformed CIDR, one '/' required" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_EXC]": { + "recorded-date": "29-11-2024, 01:41:33", + "recorded-content": { + "content_anything_but_ignorecase_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: Inside anything-but/equals-ignore-case list, number|start|null|boolean is not supported.", + "MessageRaw": "Event pattern is not valid. Reason: Inside anything-but/equals-ignore-case list, number|start|null|boolean is not supported.\n at [Source: (String)\"{\"detail\": {\"state\": [{\"anything-but\": {\"equals-ignore-case\": 123}}]}}\"; line: 1, column: 66]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_EXC]": { + "recorded-date": "29-11-2024, 01:41:36", + "recorded-content": { + "content_anything_but_ignorecase_list_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: Inside anything-but/equals-ignore-case list, number|start|null|boolean is not supported.", + "MessageRaw": "Event pattern is not valid. Reason: Inside anything-but/equals-ignore-case list, number|start|null|boolean is not supported.\n at [Source: (String)\"{\"detail\": {\"state\": [{\"anything-but\": {\"equals-ignore-case\": [123, 456]}}]}}\"; line: 1, column: 67]\n at [Source: (String)\"{\"detail\": {\"state\": [{\"anything-but\": {\"equals-ignore-case\": [123, 456]}}]}}\"; line: 1, column: 67]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_list_EXC]": { + "recorded-date": "29-11-2024, 01:41:38", + "recorded-content": { + "content_ignorecase_list_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: equals-ignore-case match pattern must be a string", + "MessageRaw": "Event pattern is not valid. Reason: equals-ignore-case match pattern must be a string\n at [Source: (String)\"{\"detail-type\": [{\"equals-ignore-case\": {\"prefix\": \"ec2\"}}]}\"; line: 1, column: 42]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[this is valid json but not a dict]": { + "recorded-date": "29-11-2024, 00:19:32", + "recorded-content": { + "invalid-pattern": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: Unrecognized token 'this': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')\n at [Source: (String)\"this is valid json but not a dict\"; line: 1, column: 5]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[{'bad': 'quotation'}]": { + "recorded-date": "29-11-2024, 00:19:32", + "recorded-content": { + "invalid-pattern": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: Unexpected character (''' (code 39)): was expecting double-quote to start field name\n at [Source: (String)\"{'bad': 'quotation'}\"; line: 1, column: 2]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[{\"not\": closed mark\"]": { + "recorded-date": "29-11-2024, 00:19:33", + "recorded-content": { + "invalid-pattern": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: Unrecognized token 'closed': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')\n at [Source: (String)\"{\"not\": closed mark\"\"; line: 1, column: 15]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[[\"not\", \"a\", \"dict\", \"but valid json\"]]": { + "recorded-date": "29-11-2024, 00:19:33", + "recorded-content": { + "invalid-pattern": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: Filter is not an object\n at [Source: (String)\"[\"not\", \"a\", \"dict\", \"but valid json\"]\"; line: 1, column: 2]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_null]": { + "recorded-date": "29-11-2024, 01:41:33", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_NEG]": { + "recorded-date": "29-11-2024, 01:41:25", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list]": { + "recorded-date": "29-11-2024, 01:41:27", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_NEG]": { + "recorded-date": "29-11-2024, 01:41:31", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard]": { + "recorded-date": "29-11-2024, 01:41:41", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_int_EXC]": { + "recorded-date": "29-11-2024, 01:41:40", + "recorded-content": { + "content_wildcard_int_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: wildcard match pattern must be a string", + "MessageRaw": "Event pattern is not valid. Reason: wildcard match pattern must be a string\n at [Source: (String)\"{\"EventBusArn\": [{\"wildcard\": 123}]}\"; line: 1, column: 34]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_list_EXC]": { + "recorded-date": "29-11-2024, 01:41:43", + "recorded-content": { + "content_wildcard_list_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: wildcard match pattern must be a string", + "MessageRaw": "Event pattern is not valid. Reason: wildcard match pattern must be a string\n at [Source: (String)\"{\"EventBusArn\": [{\"wildcard\": [\"arn::events::**:event-bus/*\"]}]}\"; line: 1, column: 32]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_type_EXC]": { + "recorded-date": "29-11-2024, 01:41:25", + "recorded-content": { + "content_anything_wildcard_list_type_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: wildcard match pattern must be a string", + "MessageRaw": "Event pattern is not valid. Reason: wildcard match pattern must be a string\n at [Source: (String)\"{\"detail\": {\"state\": [{\"anything-but\": {\"wildcard\": [123, \"*/dir/*\"]}}]}}\"; line: 1, column: 57]\n at [Source: (String)\"{\"detail\": {\"state\": [{\"anything-but\": {\"wildcard\": [123, \"*/dir/*\"]}}]}}\"; line: 1, column: 57]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_type_EXC]": { + "recorded-date": "29-11-2024, 01:41:39", + "recorded-content": { + "content_anything_wildcard_type_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: wildcard match pattern must be a string", + "MessageRaw": "Event pattern is not valid. Reason: wildcard match pattern must be a string\n at [Source: (String)\"{\"detail\": {\"FilePath\": [{\"anything-but\": {\"wildcard\": 123}}]}}\"; line: 1, column: 59]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_type_EXC]": { + "recorded-date": "29-11-2024, 01:41:24", + "recorded-content": { + "content_anything_suffix_list_type_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: prefix/suffix match pattern must be a string", + "MessageRaw": "Event pattern is not valid. Reason: prefix/suffix match pattern must be a string\n at [Source: (String)\"{\"detail\": {\"FileName\": [{\"anything-but\": {\"suffix\": [123, \".txt\"]}}]}}\"; line: 1, column: 58]\n at [Source: (String)\"{\"detail\": {\"FileName\": [{\"anything-but\": {\"suffix\": [123, \".txt\"]}}]}}\"; line: 1, column: 58]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list]": { + "recorded-date": "29-11-2024, 01:41:25", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_NEG]": { + "recorded-date": "29-11-2024, 01:41:26", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_int_EXC]": { + "recorded-date": "29-11-2024, 01:41:31", + "recorded-content": { + "content_anything_suffix_int_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: prefix/suffix match pattern must be a string", + "MessageRaw": "Event pattern is not valid. Reason: prefix/suffix match pattern must be a string\n at [Source: (String)\"{\"detail\": {\"FileName\": [{\"anything-but\": {\"suffix\": 123}}]}}\"; line: 1, column: 57]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list]": { + "recorded-date": "29-11-2024, 01:41:35", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_NEG]": { + "recorded-date": "29-11-2024, 01:41:38", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_type_EXC]": { + "recorded-date": "29-11-2024, 01:41:40", + "recorded-content": { + "content_anything_prefix_list_type_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: prefix/suffix match pattern must be a string", + "MessageRaw": "Event pattern is not valid. Reason: prefix/suffix match pattern must be a string\n at [Source: (String)\"{\"detail\": {\"state\": [{\"anything-but\": {\"prefix\": [123, \"test\"]}}]}}\"; line: 1, column: 55]\n at [Source: (String)\"{\"detail\": {\"state\": [{\"anything-but\": {\"prefix\": [123, \"test\"]}}]}}\"; line: 1, column: 55]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_int_EXC]": { + "recorded-date": "29-11-2024, 01:41:42", + "recorded-content": { + "content_anything_prefix_int_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: prefix/suffix match pattern must be a string", + "MessageRaw": "Event pattern is not valid. Reason: prefix/suffix match pattern must be a string\n at [Source: (String)\"{\"detail\": {\"state\": [{\"anything-but\": {\"prefix\": 123}}]}}\"; line: 1, column: 54]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_list_EXC]": { + "recorded-date": "29-11-2024, 01:41:28", + "recorded-content": { + "content_prefix_list_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: prefix match pattern must be a string", + "MessageRaw": "Event pattern is not valid. Reason: prefix match pattern must be a string\n at [Source: (String)\"{\"time\": [{\"prefix\": [\"2022-07-13\"]}]}\"; line: 1, column: 23]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_int_EXC]": { + "recorded-date": "29-11-2024, 01:41:34", + "recorded-content": { + "content_prefix_int_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: prefix match pattern must be a string", + "MessageRaw": "Event pattern is not valid. Reason: prefix match pattern must be a string\n at [Source: (String)\"{\"time\": [{\"prefix\": 123}]}\"; line: 1, column: 25]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_int_EXC]": { + "recorded-date": "29-11-2024, 01:41:37", + "recorded-content": { + "content_suffix_int_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: suffix match pattern must be a string", + "MessageRaw": "Event pattern is not valid. Reason: suffix match pattern must be a string\n at [Source: (String)\"{\"FileName\": [{\"suffix\": 123}]}\"; line: 1, column: 29]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_list_EXC]": { + "recorded-date": "29-11-2024, 01:41:41", + "recorded-content": { + "content_suffix_list_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: suffix match pattern must be a string", + "MessageRaw": "Event pattern is not valid. Reason: suffix match pattern must be a string\n at [Source: (String)\"{\"FileName\": [{\"suffix\": [\".png\"]}]}\"; line: 1, column: 27]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_ignorecase_EXC]": { + "recorded-date": "29-11-2024, 01:41:37", + "recorded-content": { + "content_anything_prefix_ignorecase_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: Value of anything-but must be an array or single string/number value.", + "MessageRaw": "Event pattern is not valid. Reason: Value of anything-but must be an array or single string/number value.\n at [Source: (String)\"{\"detail\": {\"FileName\": [{\"anything-but\": {\"prefix\": {\"equals-ignore-case\": \"file\"}}}]}}\"; line: 1, column: 55]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_ignorecase_EXC]": { + "recorded-date": "29-11-2024, 01:41:39", + "recorded-content": { + "content_anything_suffix_ignorecase_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: Value of anything-but must be an array or single string/number value.", + "MessageRaw": "Event pattern is not valid. Reason: Value of anything-but must be an array or single string/number value.\n at [Source: (String)\"{\"detail\": {\"FileName\": [{\"anything-but\": {\"suffix\": {\"equals-ignore-case\": \".png\"}}}]}}\"; line: 1, column: 55]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } } } diff --git a/tests/aws/services/events/test_events_patterns.validation.json b/tests/aws/services/events/test_events_patterns.validation.json index b2bff88209f39..a583a72860a51 100644 --- a/tests/aws/services/events/test_events_patterns.validation.json +++ b/tests/aws/services/events/test_events_patterns.validation.json @@ -1,249 +1,324 @@ { - "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_event_with_content_base_rule_in_pattern": { - "last_validated_date": "2024-07-11T14:14:42+00:00" - }, - "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_events_with_rule_pattern_anything_but": { - "last_validated_date": "2024-07-11T13:55:46+00:00" - }, - "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_events_with_rule_pattern_exists_false": { - "last_validated_date": "2024-07-11T13:56:06+00:00" - }, - "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_events_with_rule_pattern_exists_true": { - "last_validated_date": "2024-07-11T13:55:54+00:00" - }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays]": { - "last_validated_date": "2024-07-11T13:55:26+00:00" + "last_validated_date": "2024-11-29T01:41:25+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_NEG]": { - "last_validated_date": "2024-07-11T13:55:36+00:00" + "last_validated_date": "2024-11-29T01:41:43+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_empty_EXC]": { - "last_validated_date": "2024-07-11T13:55:29+00:00" + "last_validated_date": "2024-11-29T01:41:29+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_empty_null_NEG]": { - "last_validated_date": "2024-07-11T13:55:35+00:00" + "last_validated_date": "2024-11-29T01:41:37+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[boolean]": { - "last_validated_date": "2024-07-11T13:55:38+00:00" + "last_validated_date": "2024-11-29T01:41:44+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[boolean_NEG]": { - "last_validated_date": "2024-07-11T13:55:29+00:00" + "last_validated_date": "2024-11-29T01:41:29+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_many_rules]": { - "last_validated_date": "2024-07-11T13:55:30+00:00" + "last_validated_date": "2024-11-29T01:41:31+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_multi_match]": { - "last_validated_date": "2024-07-11T13:55:25+00:00" + "last_validated_date": "2024-11-29T01:41:24+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_multi_match_NEG]": { - "last_validated_date": "2024-07-11T13:55:27+00:00" + "last_validated_date": "2024-11-29T01:41:27+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_or]": { - "last_validated_date": "2024-07-11T13:55:32+00:00" + "last_validated_date": "2024-11-29T01:41:34+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_or_NEG]": { - "last_validated_date": "2024-07-11T13:55:32+00:00" + "last_validated_date": "2024-11-29T01:41:34+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase]": { - "last_validated_date": "2024-07-11T13:55:30+00:00" + "last_validated_date": "2024-11-29T01:41:30+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_EXC]": { + "last_validated_date": "2024-11-29T01:41:33+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_NEG]": { - "last_validated_date": "2024-07-11T13:55:36+00:00" + "last_validated_date": "2024-11-29T01:41:42+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list]": { - "last_validated_date": "2024-07-11T13:55:34+00:00" + "last_validated_date": "2024-11-29T01:41:36+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_EXC]": { + "last_validated_date": "2024-11-29T01:41:36+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_NEG]": { - "last_validated_date": "2024-07-11T13:55:26+00:00" + "last_validated_date": "2024-11-29T01:41:25+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number]": { - "last_validated_date": "2024-07-11T13:55:38+00:00" + "last_validated_date": "2024-11-29T01:41:44+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_NEG]": { - "last_validated_date": "2024-07-11T13:55:31+00:00" + "last_validated_date": "2024-11-29T01:41:32+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_list]": { - "last_validated_date": "2024-07-11T13:55:31+00:00" + "last_validated_date": "2024-11-29T01:41:31+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_list_NEG]": { - "last_validated_date": "2024-07-11T13:55:27+00:00" + "last_validated_date": "2024-11-29T01:41:28+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string]": { - "last_validated_date": "2024-07-11T13:55:27+00:00" + "last_validated_date": "2024-11-29T01:41:27+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_NEG]": { - "last_validated_date": "2024-07-11T13:55:28+00:00" + "last_validated_date": "2024-11-29T01:41:29+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list]": { - "last_validated_date": "2024-07-11T13:55:30+00:00" + "last_validated_date": "2024-11-29T01:41:30+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list_NEG]": { - "last_validated_date": "2024-07-11T13:55:35+00:00" + "last_validated_date": "2024-11-29T01:41:39+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_null]": { + "last_validated_date": "2024-11-29T01:41:33+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix]": { - "last_validated_date": "2024-07-11T13:55:33+00:00" + "last_validated_date": "2024-11-29T01:41:35+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_NEG]": { - "last_validated_date": "2024-07-11T13:55:28+00:00" + "last_validated_date": "2024-11-29T01:41:28+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_ignorecase_EXC]": { + "last_validated_date": "2024-11-29T01:41:37+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_int_EXC]": { + "last_validated_date": "2024-11-29T01:41:42+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list]": { + "last_validated_date": "2024-11-29T01:41:25+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_NEG]": { + "last_validated_date": "2024-11-29T01:41:26+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_type_EXC]": { + "last_validated_date": "2024-11-29T01:41:40+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix]": { - "last_validated_date": "2024-07-11T13:55:34+00:00" + "last_validated_date": "2024-11-29T01:41:36+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_NEG]": { - "last_validated_date": "2024-07-11T13:55:33+00:00" + "last_validated_date": "2024-11-29T01:41:35+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_ignorecase_EXC]": { + "last_validated_date": "2024-11-29T01:41:39+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_int_EXC]": { + "last_validated_date": "2024-11-29T01:41:31+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list]": { + "last_validated_date": "2024-11-29T01:41:35+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_NEG]": { + "last_validated_date": "2024-11-29T01:41:38+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_type_EXC]": { + "last_validated_date": "2024-11-29T01:41:24+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard]": { + "last_validated_date": "2024-11-29T01:41:41+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_NEG]": { + "last_validated_date": "2024-11-29T01:41:25+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list]": { + "last_validated_date": "2024-11-29T01:41:27+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_NEG]": { + "last_validated_date": "2024-11-29T01:41:31+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_type_EXC]": { + "last_validated_date": "2024-11-29T01:41:25+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_type_EXC]": { + "last_validated_date": "2024-11-29T01:41:39+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists]": { - "last_validated_date": "2024-07-11T13:55:31+00:00" + "last_validated_date": "2024-11-29T01:41:33+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_NEG]": { - "last_validated_date": "2024-07-11T13:55:37+00:00" + "last_validated_date": "2024-11-29T01:41:43+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_false]": { - "last_validated_date": "2024-07-11T13:55:36+00:00" + "last_validated_date": "2024-11-29T01:41:41+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_false_NEG]": { - "last_validated_date": "2024-07-11T13:55:37+00:00" + "last_validated_date": "2024-11-29T01:41:43+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase]": { - "last_validated_date": "2024-07-11T13:55:37+00:00" + "last_validated_date": "2024-11-29T01:41:43+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_EXC]": { + "last_validated_date": "2024-11-29T01:41:31+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_NEG]": { - "last_validated_date": "2024-07-11T13:55:36+00:00" + "last_validated_date": "2024-11-29T01:41:40+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_list_EXC]": { + "last_validated_date": "2024-11-29T01:41:38+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address]": { - "last_validated_date": "2024-07-11T13:55:28+00:00" + "last_validated_date": "2024-11-29T01:41:28+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_EXC]": { + "last_validated_date": "2024-11-29T01:41:41+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_NEG]": { - "last_validated_date": "2024-07-11T13:55:32+00:00" + "last_validated_date": "2024-11-29T01:41:33+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_EXC]": { - "last_validated_date": "2024-07-11T13:55:32+00:00" + "last_validated_date": "2024-11-29T01:41:33+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_and]": { - "last_validated_date": "2024-07-11T13:55:38+00:00" + "last_validated_date": "2024-11-29T01:41:44+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_and_NEG]": { - "last_validated_date": "2024-07-11T13:55:33+00:00" + "last_validated_date": "2024-11-29T01:41:34+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_operatorcasing_EXC]": { - "last_validated_date": "2024-07-11T13:55:27+00:00" + "last_validated_date": "2024-11-29T01:41:27+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_syntax_EXC]": { - "last_validated_date": "2024-07-11T13:55:37+00:00" + "last_validated_date": "2024-11-29T01:41:43+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix]": { - "last_validated_date": "2024-07-11T13:55:36+00:00" + "last_validated_date": "2024-11-29T01:41:40+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_NEG]": { - "last_validated_date": "2024-07-11T13:55:34+00:00" + "last_validated_date": "2024-11-29T01:41:36+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_ignorecase]": { - "last_validated_date": "2024-07-11T13:55:33+00:00" + "last_validated_date": "2024-11-29T01:41:35+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_int_EXC]": { + "last_validated_date": "2024-11-29T01:41:34+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_list_EXC]": { + "last_validated_date": "2024-11-29T01:41:28+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix]": { - "last_validated_date": "2024-07-11T13:55:36+00:00" + "last_validated_date": "2024-11-29T01:41:42+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_NEG]": { - "last_validated_date": "2024-07-11T13:55:25+00:00" + "last_validated_date": "2024-11-29T01:41:24+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_ignorecase]": { - "last_validated_date": "2024-07-11T13:55:33+00:00" + "last_validated_date": "2024-11-29T01:41:35+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_ignorecase_NEG]": { - "last_validated_date": "2024-07-11T13:55:35+00:00" + "last_validated_date": "2024-11-29T01:41:37+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_int_EXC]": { + "last_validated_date": "2024-11-29T01:41:37+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_list_EXC]": { + "last_validated_date": "2024-11-29T01:41:41+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_complex_EXC]": { - "last_validated_date": "2024-07-11T13:55:35+00:00" + "last_validated_date": "2024-11-29T01:41:38+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_int_EXC]": { + "last_validated_date": "2024-11-29T01:41:40+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_list_EXC]": { + "last_validated_date": "2024-11-29T01:41:43+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_nonrepeating]": { - "last_validated_date": "2024-07-11T13:55:26+00:00" + "last_validated_date": "2024-11-29T01:41:26+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_nonrepeating_NEG]": { - "last_validated_date": "2024-07-11T13:55:31+00:00" + "last_validated_date": "2024-11-29T01:41:32+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating]": { - "last_validated_date": "2024-07-11T13:55:25+00:00" + "last_validated_date": "2024-11-29T01:41:23+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating_NEG]": { - "last_validated_date": "2024-07-11T13:55:26+00:00" + "last_validated_date": "2024-11-29T01:41:25+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating_star_EXC]": { + "last_validated_date": "2024-11-29T01:41:26+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_simplified]": { - "last_validated_date": "2024-07-11T13:55:26+00:00" + "last_validated_date": "2024-11-29T01:41:26+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_event]": { - "last_validated_date": "2024-07-11T13:55:33+00:00" + "last_validated_date": "2024-11-29T01:41:34+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_event_NEG]": { - "last_validated_date": "2024-07-11T13:55:34+00:00" + "last_validated_date": "2024-11-29T01:41:36+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_pattern]": { - "last_validated_date": "2024-07-11T13:55:30+00:00" + "last_validated_date": "2024-11-29T01:41:30+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_pattern_NEG]": { - "last_validated_date": "2024-07-11T13:55:33+00:00" + "last_validated_date": "2024-11-29T01:41:35+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dynamodb]": { - "last_validated_date": "2024-07-11T13:55:30+00:00" + "last_validated_date": "2024-11-29T01:41:30+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_dynamodb]": { - "last_validated_date": "2024-07-11T13:55:29+00:00" + "last_validated_date": "2024-11-29T01:41:29+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_dynamodb_NEG]": { - "last_validated_date": "2024-07-11T13:55:28+00:00" + "last_validated_date": "2024-11-29T01:41:29+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[int_nolist_EXC]": { - "last_validated_date": "2024-07-11T13:55:25+00:00" + "last_validated_date": "2024-11-29T01:41:24+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[key_case_sensitive_NEG]": { - "last_validated_date": "2024-07-11T13:55:34+00:00" + "last_validated_date": "2024-11-29T01:41:35+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[list_within_dict]": { - "last_validated_date": "2024-07-11T13:55:25+00:00" + "last_validated_date": "2024-11-29T01:41:23+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[minimal]": { - "last_validated_date": "2024-07-11T13:55:36+00:00" + "last_validated_date": "2024-11-29T01:41:40+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[nested_json_NEG]": { - "last_validated_date": "2024-07-11T13:55:29+00:00" + "last_validated_date": "2024-11-29T01:41:30+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[null_value]": { - "last_validated_date": "2024-07-11T13:55:30+00:00" + "last_validated_date": "2024-11-29T01:41:31+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[null_value_NEG]": { - "last_validated_date": "2024-07-11T13:55:33+00:00" + "last_validated_date": "2024-11-29T01:41:35+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[number_comparison_float]": { - "last_validated_date": "2024-07-11T13:55:36+00:00" + "last_validated_date": "2024-11-29T01:41:42+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[operator_case_sensitive_EXC]": { - "last_validated_date": "2024-07-11T13:55:31+00:00" + "last_validated_date": "2024-11-29T01:41:32+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[operator_multiple_list]": { - "last_validated_date": "2024-07-11T13:55:30+00:00" + "last_validated_date": "2024-11-29T01:41:30+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-anything-but]": { - "last_validated_date": "2024-07-11T13:55:38+00:00" + "last_validated_date": "2024-11-29T01:41:44+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-exists-parent]": { - "last_validated_date": "2024-07-11T13:55:29+00:00" + "last_validated_date": "2024-11-29T01:41:29+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-exists]": { - "last_validated_date": "2024-07-11T13:55:26+00:00" + "last_validated_date": "2024-11-29T01:41:26+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[prefix]": { - "last_validated_date": "2024-07-11T13:55:34+00:00" + "last_validated_date": "2024-11-29T01:41:36+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[sample1]": { - "last_validated_date": "2024-07-11T13:55:34+00:00" + "last_validated_date": "2024-11-29T01:41:35+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string]": { - "last_validated_date": "2024-07-11T13:55:34+00:00" + "last_validated_date": "2024-11-29T01:41:36+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string_empty]": { - "last_validated_date": "2024-07-11T13:55:30+00:00" + "last_validated_date": "2024-11-29T01:41:30+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string_nolist_EXC]": { - "last_validated_date": "2024-07-11T13:55:28+00:00" + "last_validated_date": "2024-11-29T01:41:29+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern_source": { "last_validated_date": "2024-07-11T13:55:39+00:00" @@ -253,5 +328,29 @@ }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern_with_multi_key": { "last_validated_date": "2024-07-11T13:55:38+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[[\"not\", \"a\", \"dict\", \"but valid json\"]]": { + "last_validated_date": "2024-11-29T00:19:33+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[this is valid json but not a dict]": { + "last_validated_date": "2024-11-29T00:19:32+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[{\"not\": closed mark\"]": { + "last_validated_date": "2024-11-29T00:19:33+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[{'bad': 'quotation'}]": { + "last_validated_date": "2024-11-29T00:19:32+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_event_with_content_base_rule_in_pattern": { + "last_validated_date": "2024-07-11T14:14:42+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_events_with_rule_pattern_anything_but": { + "last_validated_date": "2024-07-11T13:55:46+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_events_with_rule_pattern_exists_false": { + "last_validated_date": "2024-07-11T13:56:06+00:00" + }, + "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_events_with_rule_pattern_exists_true": { + "last_validated_date": "2024-07-11T13:55:54+00:00" } } diff --git a/tests/unit/utils/test_event_matcher.py b/tests/unit/utils/test_event_matcher.py index 59e348af2f0a8..436aa1b7c15be 100644 --- a/tests/unit/utils/test_event_matcher.py +++ b/tests/unit/utils/test_event_matcher.py @@ -3,6 +3,7 @@ import pytest from localstack import config +from localstack.aws.api.events import InvalidEventPatternException from localstack.utils.event_matcher import matches_event EVENT_PATTERN_DICT = { @@ -68,9 +69,20 @@ def test_matches_event_non_matching_pattern(): assert not matches_event(non_matching_pattern, EVENT_DICT) -def test_matches_event_invalid_json(): +@pytest.mark.parametrize("engine", ("python", "java")) +def test_matches_event_invalid_json(event_rule_engine, engine): """Test with invalid JSON strings""" - with pytest.raises(json.JSONDecodeError): + + if engine == "java": + # this lets the exception bubble up to the provider, when AWS returns a proper exception, it should be fixed + exception_type = json.JSONDecodeError + # do not re-enable this test, enabling jpype here will break StepFunctions + pytest.skip("jpype conflict") + else: + exception_type = InvalidEventPatternException + + event_rule_engine(engine) + with pytest.raises(exception_type): matches_event("{invalid-json}", EVENT_STR) From 21210ce51c7602219c5d70c4d8300a33085477c0 Mon Sep 17 00:00:00 2001 From: Joel Scheuner Date: Fri, 29 Nov 2024 16:52:33 +0100 Subject: [PATCH 35/38] Add deprecation for Java-based event ruler (#11964) --- localstack-core/localstack/config.py | 3 ++- localstack-core/localstack/deprecations.py | 13 ++++++++++--- .../lambda_/event_source_mapping/pollers/poller.py | 2 -- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/localstack-core/localstack/config.py b/localstack-core/localstack/config.py index 58c76cdbdf586..eee306feb4481 100644 --- a/localstack-core/localstack/config.py +++ b/localstack-core/localstack/config.py @@ -846,9 +846,10 @@ def populate_edge_configuration( # get-function call. INTERNAL_RESOURCE_ACCOUNT = os.environ.get("INTERNAL_RESOURCE_ACCOUNT") or "949334387222" +# TODO: remove with 4.1.0 # Determine which implementation to use for the event rule / event filtering engine used by multiple services: # EventBridge, EventBridge Pipes, Lambda Event Source Mapping -# Options: python (default) | java (preview) +# Options: python (default) | java (deprecated since 4.0.3) EVENT_RULE_ENGINE = os.environ.get("EVENT_RULE_ENGINE", "python").strip() # ----- diff --git a/localstack-core/localstack/deprecations.py b/localstack-core/localstack/deprecations.py index fb1f32a36c68a..3bcbe735124ec 100644 --- a/localstack-core/localstack/deprecations.py +++ b/localstack-core/localstack/deprecations.py @@ -269,6 +269,11 @@ def is_affected(self) -> bool: "0.14.0", "This option has no effect anymore. Please use OPENSEARCH_ENDPOINT_STRATEGY instead.", ), + EnvVarDeprecation( + "PERSIST_ALL", + "2.3.2", + "LocalStack treats backends and assets the same with respect to persistence. Please remove PERSIST_ALL.", + ), EnvVarDeprecation( "DNS_LOCAL_NAME_PATTERNS", "3.0.0", @@ -299,9 +304,11 @@ def is_affected(self) -> bool: " Please remove PROVIDER_OVERRIDE_STEPFUNCTIONS.", ), EnvVarDeprecation( - "PERSIST_ALL", - "2.3.2", - "LocalStack treats backends and assets the same with respect to persistence. Please remove PERSIST_ALL.", + "EVENT_RULE_ENGINE", + "4.0.3", + "The Java-based event ruler is deprecated because our latest Python-native implementation introduced in 4.0.3" + " is faster, achieves great AWS parity, and fixes compatibility issues with the StepFunctions JSONata feature." + " Please remove EVENT_RULE_ENGINE.", ), ] diff --git a/localstack-core/localstack/services/lambda_/event_source_mapping/pollers/poller.py b/localstack-core/localstack/services/lambda_/event_source_mapping/pollers/poller.py index a4e068c08208f..272804f6f5a3d 100644 --- a/localstack-core/localstack/services/lambda_/event_source_mapping/pollers/poller.py +++ b/localstack-core/localstack/services/lambda_/event_source_mapping/pollers/poller.py @@ -21,8 +21,6 @@ class PipeStateReasonValues(PipeStateReason): # TODO: add others (e.g., failure) -POLL_INTERVAL_SEC: float = 1 - LOG = logging.getLogger(__name__) From 52d4e4fbeddf84e45ac9d0e956a1ced878c8d7c5 Mon Sep 17 00:00:00 2001 From: Giovanni Grano Date: Fri, 29 Nov 2024 14:56:08 -0500 Subject: [PATCH 36/38] fix: follow-up for null value in SES response (#11966) --- localstack-core/localstack/openapi.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/localstack-core/localstack/openapi.yaml b/localstack-core/localstack/openapi.yaml index 1a78bfe3d0e28..b3656c3f6f1af 100644 --- a/localstack-core/localstack/openapi.yaml +++ b/localstack-core/localstack/openapi.yaml @@ -158,11 +158,10 @@ components: additionalProperties: false properties: html_part: - type: [string, 'null'] + type: string text_part: type: string required: - - html_part - text_part type: object Destination: From e0e3ec26db13b71bb43893ed6e107f2888bae654 Mon Sep 17 00:00:00 2001 From: Mathieu Cloutier <79954947+cloutierMat@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:07:42 -0700 Subject: [PATCH 37/38] APIGW: fix parsing invalid JSON template in MOCK integration (#11967) --- .../next_gen/execute_api/integrations/mock.py | 64 +++++++++++++++++-- .../test_apigateway_integrations.py | 12 ++-- ...test_apigateway_integrations.snapshot.json | 22 +++++++ ...st_apigateway_integrations.validation.json | 2 +- .../apigateway/test_mock_integration.py | 28 ++++++++ 5 files changed, 118 insertions(+), 10 deletions(-) diff --git a/localstack-core/localstack/services/apigateway/next_gen/execute_api/integrations/mock.py b/localstack-core/localstack/services/apigateway/next_gen/execute_api/integrations/mock.py index d4f2038422184..731a8b8f4f245 100644 --- a/localstack-core/localstack/services/apigateway/next_gen/execute_api/integrations/mock.py +++ b/localstack-core/localstack/services/apigateway/next_gen/execute_api/integrations/mock.py @@ -1,5 +1,6 @@ import json import logging +import re from json import JSONDecodeError from werkzeug.datastructures import Headers @@ -39,20 +40,73 @@ def invoke(self, context: RestApiInvocationContext) -> EndpointResponse: return EndpointResponse(status_code=status_code, body=b"", headers=Headers()) - @staticmethod - def get_status_code(integration_req: IntegrationRequest) -> int | None: + def get_status_code(self, integration_req: IntegrationRequest) -> int | None: try: - body = json.loads(to_str(integration_req["body"])) + body = json.loads(integration_req["body"]) except JSONDecodeError as e: LOG.debug( - "Exception while parsing integration request body: %s", + "Exception while JSON parsing integration request body: %s" + "Falling back to custom parser", e, exc_info=LOG.isEnabledFor(logging.DEBUG), ) - return + body = self.parse_invalid_json(to_str(integration_req["body"])) status_code = body.get("statusCode") if not isinstance(status_code, int): return return status_code + + def parse_invalid_json(self, body: str) -> dict: + """This is a quick fix to unblock cdk users setting cors policy for rest apis. + CDK creates a MOCK OPTIONS route with in valid json. `{statusCode: 200}` + Aws probably has a custom token parser. We can implement one + at some point if we have user requests for it""" + try: + statuscode = "" + matched = re.match(r"^\s*{(.+)}\s*$", body).group(1) + splits = [m.strip() for m in matched.split(",")] + # TODO this is not right, but nested object would otherwise break the parsing + kvs = [s.split(":", maxsplit=1) for s in splits] + for kv in kvs: + assert len(kv) == 2 + k, v = kv + k = k.strip() + v = v.strip() + + assert k + assert v + + if k == "statusCode": + statuscode = int(v) + continue + + if (first_char := k[0]) in "[{": + raise Exception + if first_char in "'\"": + assert len(k) > 2 + assert k[-1] == first_char + k = k[1:-1] + + if (v_first_char := v[0]) in "[{'\"": + assert len(v) > 2 + if v_first_char == "{": + # TODO reparse objects + assert v[-1] == "}" + elif v_first_char == "[": + # TODO validate arrays + assert v[-1] == "]" + else: + assert v[-1] == v_first_char + v = v[1:-1] + + if k == "statusCode": + statuscode = int(v) + + return {"statusCode": statuscode} + except Exception as e: + LOG.debug( + "Error Parsing an invalid json, %s", e, exc_info=LOG.isEnabledFor(logging.DEBUG) + ) + return {"statusCode": ""} diff --git a/tests/aws/services/apigateway/test_apigateway_integrations.py b/tests/aws/services/apigateway/test_apigateway_integrations.py index 1e7249d5030c4..d9780595186c8 100644 --- a/tests/aws/services/apigateway/test_apigateway_integrations.py +++ b/tests/aws/services/apigateway/test_apigateway_integrations.py @@ -548,10 +548,11 @@ def test_put_integration_validation( @markers.aws.validated @pytest.mark.skipif( - condition=not is_next_gen_api(), + condition=not is_next_gen_api() and not is_aws_cloud(), reason="Behavior is properly implemented in Legacy, it returns the MOCK response", ) -def test_integration_mock_with_path_param(create_rest_apigw, aws_client): +def test_integration_mock_with_path_param(create_rest_apigw, aws_client, snapshot): + snapshot.add_transformer(snapshot.transform.key_value("cacheNamespace")) api_id, _, root = create_rest_apigw( name=f"test-api-{short_uid()}", description="this is my api", @@ -580,7 +581,7 @@ def test_integration_mock_with_path_param(create_rest_apigw, aws_client): # you don't have to pass URI for Mock integration as it's not used anyway # when exporting an API in AWS, apparently you can get integration path parameters even if not used - aws_client.apigateway.put_integration( + integration = aws_client.apigateway.put_integration( restApiId=api_id, resourceId=resource_id, httpMethod="GET", @@ -589,8 +590,11 @@ def test_integration_mock_with_path_param(create_rest_apigw, aws_client): requestParameters={ "integration.request.path.integrationPath": "method.request.path.testPath", }, - requestTemplates={"application/json": '{"statusCode": 200}'}, + # This template was modified to validate a cdk issue where it creates this template part + # of some L2 construct for CORS handling. This isn't valid JSON but accepted by aws. + requestTemplates={"application/json": "{statusCode: 200}"}, ) + snapshot.match("integration", integration) aws_client.apigateway.put_integration_response( restApiId=api_id, diff --git a/tests/aws/services/apigateway/test_apigateway_integrations.snapshot.json b/tests/aws/services/apigateway/test_apigateway_integrations.snapshot.json index 14879be5d5275..9c8acd6361159 100644 --- a/tests/aws/services/apigateway/test_apigateway_integrations.snapshot.json +++ b/tests/aws/services/apigateway/test_apigateway_integrations.snapshot.json @@ -1056,5 +1056,27 @@ "response": "this is the else clause" } } + }, + "tests/aws/services/apigateway/test_apigateway_integrations.py::test_integration_mock_with_path_param": { + "recorded-date": "29-11-2024, 19:27:54", + "recorded-content": { + "integration": { + "cacheKeyParameters": [], + "cacheNamespace": "", + "passthroughBehavior": "WHEN_NO_MATCH", + "requestParameters": { + "integration.request.path.integrationPath": "method.request.path.testPath" + }, + "requestTemplates": { + "application/json": "{statusCode: 200}" + }, + "timeoutInMillis": 29000, + "type": "MOCK", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + } + } } } diff --git a/tests/aws/services/apigateway/test_apigateway_integrations.validation.json b/tests/aws/services/apigateway/test_apigateway_integrations.validation.json index f13c70ac220ba..9af58354dd52e 100644 --- a/tests/aws/services/apigateway/test_apigateway_integrations.validation.json +++ b/tests/aws/services/apigateway/test_apigateway_integrations.validation.json @@ -15,7 +15,7 @@ "last_validated_date": "2024-04-15T23:07:07+00:00" }, "tests/aws/services/apigateway/test_apigateway_integrations.py::test_integration_mock_with_path_param": { - "last_validated_date": "2024-11-05T12:55:51+00:00" + "last_validated_date": "2024-11-29T19:27:54+00:00" }, "tests/aws/services/apigateway/test_apigateway_integrations.py::test_integration_mock_with_request_overrides_in_response_template": { "last_validated_date": "2024-11-06T23:09:04+00:00" diff --git a/tests/unit/services/apigateway/test_mock_integration.py b/tests/unit/services/apigateway/test_mock_integration.py index beadf423b9e13..fca3de5a3bc44 100644 --- a/tests/unit/services/apigateway/test_mock_integration.py +++ b/tests/unit/services/apigateway/test_mock_integration.py @@ -51,3 +51,31 @@ def test_mock_integration(self, create_default_context): with pytest.raises(InternalServerError) as exc_info: mock_integration.invoke(ctx) assert exc_info.match("Internal server error") + + def test_custom_parser(self, create_default_context): + mock_integration = RestApiMockIntegration() + + valid_templates = [ + "{statusCode: 200,super{ f}oo: [ba r]}", + "{statusCode: 200, \"value\": 'goog'}", + "{statusCode: 200, foo}: [ba r]}", + "{statusCode: 200, foo'}: [ba r]}", + "{statusCode: 200, }foo: [ba r]}", + ] + invalid_templates = [ + "statusCode: 200", + "{statusCode: 200, {foo: [ba r]}", + # This test fails as we do not support nested objects + # "{statusCode: 200, what:{}foo: [ba r]}}" + ] + + for valid_template in valid_templates: + ctx = create_default_context(body=valid_template) + response = mock_integration.invoke(ctx) + assert response["status_code"] == 200 + + for invalid_template in invalid_templates: + ctx = create_default_context(body=invalid_template) + with pytest.raises(InternalServerError) as exc_info: + mock_integration.invoke(ctx) + assert exc_info.match("Internal server error") From aa795ed1c04a8285c01c96aa7ab79c17489f5766 Mon Sep 17 00:00:00 2001 From: "localstack[bot]" Date: Fri, 29 Nov 2024 20:41:53 +0000 Subject: [PATCH 38/38] release version 4.0.3