From 20c65adfe807c8cdf1b2f5dbd84e49b2e3bc3fe0 Mon Sep 17 00:00:00 2001 From: MEPalma Date: Fri, 25 Aug 2023 20:47:32 +0200 Subject: [PATCH] support for tagging --- .../service/state_task_service_sqs.py | 4 +- .../stepfunctions/backend/state_machine.py | 41 ++ .../services/stepfunctions/provider_v2.py | 46 ++ .../stepfunctions/v2/test_sfn_api_tagging.py | 190 ++++++ .../v2/test_sfn_api_tagging.snapshot.json | 543 ++++++++++++++++++ 5 files changed, 822 insertions(+), 2 deletions(-) create mode 100644 tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py create mode 100644 tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.snapshot.json diff --git a/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_sqs.py b/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_sqs.py index 7608ef02fda2b..9c207afc24b90 100644 --- a/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_sqs.py +++ b/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_sqs.py @@ -4,6 +4,7 @@ from botocore.exceptions import ClientError from localstack.aws.api.stepfunctions import HistoryEventType, TaskFailedEventDetails +from localstack.aws.connect import connect_externally_to from localstack.services.stepfunctions.asl.component.common.error_name.custom_error_name import ( CustomErrorName, ) @@ -16,7 +17,6 @@ from localstack.services.stepfunctions.asl.eval.environment import Environment from localstack.services.stepfunctions.asl.eval.event.event_detail import EventDetails from localstack.services.stepfunctions.asl.utils.encoding import to_json_str -from localstack.utils.aws import aws_stack from localstack.utils.strings import camel_to_snake_case @@ -65,7 +65,7 @@ def _eval_service_task(self, env: Environment, parameters: dict) -> None: parameters["MessageBody"] = to_json_str(message_body) api_action = camel_to_snake_case(self.resource.api_action) - sqs_client = aws_stack.connect_to_service("sqs", config=Config(parameter_validation=False)) + sqs_client = connect_externally_to(config=Config(parameter_validation=False)).sqs response = getattr(sqs_client, api_action)(**parameters) response.pop("ResponseMetadata", None) env.stack.append(response) diff --git a/localstack/services/stepfunctions/backend/state_machine.py b/localstack/services/stepfunctions/backend/state_machine.py index ea19929e2485d..431d187c1d083 100644 --- a/localstack/services/stepfunctions/backend/state_machine.py +++ b/localstack/services/stepfunctions/backend/state_machine.py @@ -2,6 +2,7 @@ import abc import json +from collections import OrderedDict from datetime import datetime from typing import Final, Optional @@ -16,8 +17,11 @@ StateMachineStatus, StateMachineType, StateMachineVersionListItem, + Tag, + TagKeyList, TagList, TracingConfiguration, + ValidationException, ) from localstack.utils.strings import long_uid @@ -78,8 +82,44 @@ def itemise(self): class StateMachineRevision(StateMachineInstance): + class TagManager: + _tags: Final[dict[str, Optional[str]]] + + def __init__(self): + self._tags = OrderedDict() + + @staticmethod + def _validate_key_value(key: str) -> None: + if not key: + raise ValidationException() + + @staticmethod + def _validate_tag_value(value: str) -> None: + if value is None: + raise ValidationException() + + def add_all(self, tags: TagList) -> None: + for tag in tags: + tag_key = tag["key"] + tag_value = tag["value"] + self._validate_key_value(key=tag_key) + self._validate_tag_value(value=tag_value) + self._tags[tag_key] = tag_value + + def remove_all(self, keys: TagKeyList): + for key in keys: + self._validate_key_value(key=key) + self._tags.pop(key, None) + + def to_tag_list(self) -> TagList: + tag_list = list() + for key, value in self._tags.items(): + tag_list.append(Tag(key=key, value=value)) + return tag_list + _next_version_number: int versions: Final[dict[RevisionId, Arn]] + tag_manager: Final[TagManager] def __init__( self, @@ -106,6 +146,7 @@ def __init__( ) self.versions = dict() self._version_number = 0 + self.tag_manager = StateMachineRevision.TagManager() def create_revision( self, definition: Optional[str], role_arn: Optional[Arn] diff --git a/localstack/services/stepfunctions/provider_v2.py b/localstack/services/stepfunctions/provider_v2.py index dd2ed0734696f..4f5fae3a7f42a 100644 --- a/localstack/services/stepfunctions/provider_v2.py +++ b/localstack/services/stepfunctions/provider_v2.py @@ -29,6 +29,7 @@ ListExecutionsPageToken, ListStateMachinesOutput, ListStateMachineVersionsOutput, + ListTagsForResourceOutput, LoggingConfiguration, LongArn, MissingRequiredParameter, @@ -37,6 +38,7 @@ PageToken, Publish, PublishStateMachineVersionOutput, + ResourceNotFound, ReverseOrder, RevisionId, SendTaskFailureOutput, @@ -52,11 +54,15 @@ StateMachineType, StepfunctionsApi, StopExecutionOutput, + TagKeyList, + TagList, + TagResourceOutput, TaskDoesNotExist, TaskTimedOut, TaskToken, TraceHeader, TracingConfiguration, + UntagResourceOutput, UpdateStateMachineOutput, ValidationException, VersionDescription, @@ -199,6 +205,10 @@ def create_state_machine( tracing_config=request.get("tracingConfiguration"), ) + tags = request.get("tags") + if tags: + state_machine.tag_manager.add_all(tags) + state_machines[arn] = state_machine create_output = CreateStateMachineOutput( @@ -538,3 +548,39 @@ def publish_state_machine_version( creationDate=state_machine_version.create_date, stateMachineVersionArn=state_machine_version.arn, ) + + def tag_resource( + self, context: RequestContext, resource_arn: Arn, tags: TagList + ) -> TagResourceOutput: + # TODO: add tagging for activities. + state_machines = self.get_store(context).state_machines + state_machine = state_machines.get(resource_arn) + if not isinstance(state_machine, StateMachineRevision): + raise ResourceNotFound(f"Resource not found: '{resource_arn}'") + + state_machine.tag_manager.add_all(tags) + return TagResourceOutput() + + def untag_resource( + self, context: RequestContext, resource_arn: Arn, tag_keys: TagKeyList + ) -> UntagResourceOutput: + # TODO: add untagging for activities. + state_machines = self.get_store(context).state_machines + state_machine = state_machines.get(resource_arn) + if not isinstance(state_machine, StateMachineRevision): + raise ResourceNotFound(f"Resource not found: '{resource_arn}'") + + state_machine.tag_manager.remove_all(tag_keys) + return UntagResourceOutput() + + def list_tags_for_resource( + self, context: RequestContext, resource_arn: Arn + ) -> ListTagsForResourceOutput: + # TODO: add untagging for activities. + state_machines = self.get_store(context).state_machines + state_machine = state_machines.get(resource_arn) + if not isinstance(state_machine, StateMachineRevision): + raise ResourceNotFound(f"Resource not found: '{resource_arn}'") + + tags: TagList = state_machine.tag_manager.to_tag_list() + return ListTagsForResourceOutput(tags=tags) diff --git a/tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py b/tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py new file mode 100644 index 0000000000000..8d4a20b51cc58 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py @@ -0,0 +1,190 @@ +import json + +import pytest + +from localstack.aws.api.stepfunctions import Tag +from localstack.testing.pytest import markers +from localstack.testing.snapshots.transformer import RegexTransformer +from localstack.utils.strings import short_uid +from tests.aws.services.stepfunctions.templates.base.base_templates import BaseTemplate +from tests.aws.services.stepfunctions.utils import is_old_provider + +pytestmark = pytest.mark.skipif( + condition=is_old_provider(), reason="Test suite for v2 provider only." +) + + +@markers.snapshot.skip_snapshot_verify( + paths=["$..loggingConfiguration", "$..tracingConfiguration", "$..previousEventId"] +) +class TestSnfApiTagging: + @markers.aws.validated + @pytest.mark.parametrize( + "tag_list", + [ + [], + [Tag(key="key1", value="value1")], + [Tag(key="key1", value="")], + [Tag(key="key1", value="value1"), Tag(key="key1", value="value1")], + [Tag(key="key1", value="value1"), Tag(key="key2", value="value2")], + ], + ) + def test_tag_state_machine( + self, create_iam_role_for_sfn, create_state_machine, sfn_snapshot, aws_client, tag_list + ): + snf_role_arn = create_iam_role_for_sfn() + sfn_snapshot.add_transformer(RegexTransformer(snf_role_arn, "snf_role_arn")) + + definition = BaseTemplate.load_sfn_template(BaseTemplate.BASE_PASS_RESULT) + definition_str = json.dumps(definition) + + sm_name = f"statemachine_{short_uid()}" + creation_resp_1 = create_state_machine( + name=sm_name, definition=definition_str, roleArn=snf_role_arn + ) + state_machine_arn = creation_resp_1["stateMachineArn"] + sfn_snapshot.add_transformer(sfn_snapshot.transform.sfn_sm_create_arn(creation_resp_1, 0)) + sfn_snapshot.match("creation_resp_1", creation_resp_1) + + tag_resource_resp = aws_client.stepfunctions.tag_resource( + resourceArn=state_machine_arn, tags=tag_list + ) + sfn_snapshot.match("tag_resource_resp", tag_resource_resp) + + list_resources_res = aws_client.stepfunctions.list_tags_for_resource( + resourceArn=state_machine_arn + ) + sfn_snapshot.match("list_resources_res", list_resources_res) + + @markers.aws.validated + @pytest.mark.parametrize( + "tag_list", + [ + None, + [Tag(key="", value="value")], + [Tag(key=None, value="value")], + [Tag(key="key1", value=None)], + ], + ) + def test_tag_invalid_state_machine( + self, create_iam_role_for_sfn, create_state_machine, sfn_snapshot, aws_client, tag_list + ): + snf_role_arn = create_iam_role_for_sfn() + sfn_snapshot.add_transformer(RegexTransformer(snf_role_arn, "snf_role_arn")) + + definition = BaseTemplate.load_sfn_template(BaseTemplate.BASE_PASS_RESULT) + definition_str = json.dumps(definition) + + sm_name = f"statemachine_{short_uid()}" + creation_resp_1 = create_state_machine( + name=sm_name, definition=definition_str, roleArn=snf_role_arn + ) + state_machine_arn = creation_resp_1["stateMachineArn"] + sfn_snapshot.add_transformer(sfn_snapshot.transform.sfn_sm_create_arn(creation_resp_1, 0)) + sfn_snapshot.match("creation_resp_1", creation_resp_1) + + with pytest.raises(Exception) as error: + aws_client.stepfunctions.tag_resource(resourceArn=state_machine_arn, tags=tag_list) + sfn_snapshot.match("error", error.value) + + @markers.aws.validated + def test_tag_state_machine_version( + self, + create_iam_role_for_sfn, + create_state_machine, + sfn_snapshot, + aws_client, + ): + snf_role_arn = create_iam_role_for_sfn() + sfn_snapshot.add_transformer(RegexTransformer(snf_role_arn, "snf_role_arn")) + + definition = BaseTemplate.load_sfn_template(BaseTemplate.BASE_PASS_RESULT) + definition_str = json.dumps(definition) + + sm_name = f"statemachine_{short_uid()}" + creation_resp_1 = create_state_machine( + name=sm_name, definition=definition_str, roleArn=snf_role_arn + ) + state_machine_arn = creation_resp_1["stateMachineArn"] + sfn_snapshot.add_transformer(sfn_snapshot.transform.sfn_sm_create_arn(creation_resp_1, 0)) + sfn_snapshot.match("creation_resp_1", creation_resp_1) + + publish_resp = aws_client.stepfunctions.publish_state_machine_version( + stateMachineArn=state_machine_arn + ) + state_machine_version_arn = publish_resp["stateMachineVersionArn"] + sfn_snapshot.match("publish_resp", publish_resp) + + with pytest.raises(Exception) as error: + aws_client.stepfunctions.tag_resource( + resourceArn=state_machine_version_arn, tags=[Tag(key="key1", value="value1")] + ) + sfn_snapshot.match("error", error.value) + + @markers.aws.validated + @pytest.mark.parametrize( + "tag_keys", + [ + [], + ["key1"], + ["key1", "key1"], + ["key1", "key2"], + ], + ) + def test_untag_state_machine( + self, create_iam_role_for_sfn, create_state_machine, sfn_snapshot, aws_client, tag_keys + ): + snf_role_arn = create_iam_role_for_sfn() + sfn_snapshot.add_transformer(RegexTransformer(snf_role_arn, "snf_role_arn")) + + definition = BaseTemplate.load_sfn_template(BaseTemplate.BASE_PASS_RESULT) + definition_str = json.dumps(definition) + + sm_name = f"statemachine_{short_uid()}" + creation_resp_1 = create_state_machine( + name=sm_name, definition=definition_str, roleArn=snf_role_arn + ) + state_machine_arn = creation_resp_1["stateMachineArn"] + sfn_snapshot.add_transformer(sfn_snapshot.transform.sfn_sm_create_arn(creation_resp_1, 0)) + sfn_snapshot.match("creation_resp_1", creation_resp_1) + + tag_resource_resp = aws_client.stepfunctions.tag_resource( + resourceArn=state_machine_arn, tags=[Tag(key="key1", value="value1")] + ) + sfn_snapshot.match("tag_resource_resp", tag_resource_resp) + + untag_resource_resp = aws_client.stepfunctions.untag_resource( + resourceArn=state_machine_arn, tagKeys=tag_keys + ) + sfn_snapshot.match("untag_resource_resp", untag_resource_resp) + + list_resources_res = aws_client.stepfunctions.list_tags_for_resource( + resourceArn=state_machine_arn + ) + sfn_snapshot.match("list_resources_res", list_resources_res) + + @markers.aws.validated + def test_create_state_machine( + self, create_iam_role_for_sfn, create_state_machine, sfn_snapshot, aws_client + ): + snf_role_arn = create_iam_role_for_sfn() + sfn_snapshot.add_transformer(RegexTransformer(snf_role_arn, "snf_role_arn")) + + definition = BaseTemplate.load_sfn_template(BaseTemplate.BASE_PASS_RESULT) + definition_str = json.dumps(definition) + + sm_name = f"statemachine_{short_uid()}" + creation_resp_1 = create_state_machine( + name=sm_name, + definition=definition_str, + roleArn=snf_role_arn, + tags=[Tag(key="key1", value="value1"), Tag(key="key2", value="value2")], + ) + state_machine_arn = creation_resp_1["stateMachineArn"] + sfn_snapshot.add_transformer(sfn_snapshot.transform.sfn_sm_create_arn(creation_resp_1, 0)) + sfn_snapshot.match("creation_resp_1", creation_resp_1) + + list_resources_res = aws_client.stepfunctions.list_tags_for_resource( + resourceArn=state_machine_arn + ) + sfn_snapshot.match("list_resources_res", list_resources_res) diff --git a/tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.snapshot.json b/tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.snapshot.json new file mode 100644 index 0000000000000..d14e7b39f57be --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.snapshot.json @@ -0,0 +1,543 @@ +{ + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_keys0]": { + "recorded-date": "25-08-2023, 19:28:20", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "untag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_resources_res": { + "tags": [ + { + "key": "key1", + "value": "value1" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_keys1]": { + "recorded-date": "25-08-2023, 19:28:35", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "untag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_resources_res": { + "tags": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_keys2]": { + "recorded-date": "25-08-2023, 19:28:50", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "untag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_resources_res": { + "tags": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_keys3]": { + "recorded-date": "25-08-2023, 19:29:05", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "untag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_resources_res": { + "tags": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_list0]": { + "recorded-date": "25-08-2023, 20:18:59", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_resources_res": { + "tags": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_list2]": { + "recorded-date": "25-08-2023, 20:19:28", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_resources_res": { + "tags": [ + { + "key": "key1", + "value": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_list3]": { + "recorded-date": "25-08-2023, 20:19:41", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_resources_res": { + "tags": [ + { + "key": "key1", + "value": "value1" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_invalid_state_machine[tag_list0]": { + "recorded-date": "25-08-2023, 19:37:31", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "resource_not_found": "Parameter validation failed:\nInvalid length for parameter tags[0].key, value: 0, valid min length: 1" + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_invalid_state_machine[tag_list1]": { + "recorded-date": "25-08-2023, 20:20:27", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "error": "Parameter validation failed:\nInvalid length for parameter tags[0].key, value: 0, valid min length: 1" + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_invalid_state_machine[tag_list3]": { + "recorded-date": "25-08-2023, 20:20:55", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "error": "Parameter validation failed:\nInvalid type for parameter tags[0].value, value: None, type: , valid types: " + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_list1]": { + "recorded-date": "25-08-2023, 20:19:13", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_resources_res": { + "tags": [ + { + "key": "key1", + "value": "value1" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_list4]": { + "recorded-date": "25-08-2023, 20:19:55", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_resources_res": { + "tags": [ + { + "key": "key1", + "value": "value1" + }, + { + "key": "key2", + "value": "value2" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_invalid_state_machine[tag_list2]": { + "recorded-date": "25-08-2023, 20:20:41", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "error": "Parameter validation failed:\nInvalid type for parameter tags[0].key, value: None, type: , valid types: " + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine_version": { + "recorded-date": "25-08-2023, 20:21:09", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "publish_resp": { + "creationDate": "datetime", + "stateMachineVersionArn": "arn:aws:states::111111111111:stateMachine::1", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "error": "An error occurred (ResourceNotFound) when calling the TagResource operation: Resource not found: 'arn:aws:states::111111111111:stateMachine::1'" + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_untag_state_machine[tag_keys0]": { + "recorded-date": "25-08-2023, 20:21:22", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "untag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_resources_res": { + "tags": [ + { + "key": "key1", + "value": "value1" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_untag_state_machine[tag_keys1]": { + "recorded-date": "25-08-2023, 20:21:37", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "untag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_resources_res": { + "tags": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_untag_state_machine[tag_keys2]": { + "recorded-date": "25-08-2023, 20:21:51", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "untag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_resources_res": { + "tags": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_untag_state_machine[tag_keys3]": { + "recorded-date": "25-08-2023, 20:22:05", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "untag_resource_resp": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_resources_res": { + "tags": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_invalid_state_machine[None]": { + "recorded-date": "25-08-2023, 20:20:14", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "error": "Parameter validation failed:\nInvalid type for parameter tags, value: None, type: , valid types: , " + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_create_state_machine": { + "recorded-date": "25-08-2023, 20:35:47", + "recorded-content": { + "creation_resp_1": { + "creationDate": "datetime", + "stateMachineArn": "arn:aws:states::111111111111:stateMachine:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_resources_res": { + "tags": [ + { + "key": "key1", + "value": "value1" + }, + { + "key": "key2", + "value": "value2" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + } +}