From 0f133ea04469accdb8cbdd98269d52bafdea3ce8 Mon Sep 17 00:00:00 2001 From: William Gaul Date: Wed, 29 Oct 2025 09:44:27 -0700 Subject: [PATCH] feat: Support asynchronous shareable test events This feature was added recently to the Lambda console. It works by storing event metadata as an `x-metadata` OpenAPI extension on the schema's example. Here we support putting an event with a desired `--invocation-type` and passing that to a remote invoke (with an explicitly provided invocation type `--parameter` taking precedence). --- Makefile | 3 +- samcli/commands/remote/invoke/cli.py | 9 +- samcli/commands/remote/test_event/get/cli.py | 2 +- samcli/commands/remote/test_event/put/cli.py | 15 +- .../remote/test_event/put/core/options.py | 2 +- .../lambda_shared_test_event.py | 34 +++-- samcli/lib/utils/invocation_type.py | 6 + tests/unit/commands/remote/invoke/test_cli.py | 138 +++++++++++++++++- .../commands/remote/test_event/test_cli.py | 12 +- .../test_lambda_shared_test_event.py | 52 ++++++- 10 files changed, 250 insertions(+), 23 deletions(-) create mode 100644 samcli/lib/utils/invocation_type.py diff --git a/Makefile b/Makefile index f7b9c51b433..6482cb79328 100644 --- a/Makefile +++ b/Makefile @@ -13,8 +13,7 @@ init: fi test: - # Run unit tests - # Fail if coverage falls below 95% + # Run unit tests and fail if coverage falls below 94% pytest --cov samcli --cov schema --cov-report term-missing --cov-fail-under 94 tests/unit test-cov-report: diff --git a/samcli/commands/remote/invoke/cli.py b/samcli/commands/remote/invoke/cli.py index 2d7d3ef71b0..b9919fda71f 100644 --- a/samcli/commands/remote/invoke/cli.py +++ b/samcli/commands/remote/invoke/cli.py @@ -166,10 +166,15 @@ def do_cli( and remote_invoke_context.resource_summary and remote_invoke_context.resource_summary.resource_type == AWS_LAMBDA_FUNCTION ): - lambda_test_event = remote_invoke_context.get_lambda_shared_test_event_provider() LOG.debug("Retrieving remote event %s", test_event_name) - event = lambda_test_event.get_event(test_event_name, remote_invoke_context.resource_summary) + lambda_test_event = remote_invoke_context.get_lambda_shared_test_event_provider().get_event( + test_event_name, remote_invoke_context.resource_summary + ) + event = lambda_test_event["json"] LOG.debug("Remote event contents: %s", event) + metadata = lambda_test_event["metadata"] + if "invocationType" in metadata: + parameter.setdefault("InvocationType", metadata["invocationType"]) elif test_event_name: LOG.info("Note: remote event is only supported for AWS Lambda Function resource.") test_event_name = "" diff --git a/samcli/commands/remote/test_event/get/cli.py b/samcli/commands/remote/test_event/get/cli.py index e8685ca41a8..2ea5687e7d3 100644 --- a/samcli/commands/remote/test_event/get/cli.py +++ b/samcli/commands/remote/test_event/get/cli.py @@ -127,7 +127,7 @@ def do_cli( raise UserException(str(ex), wrapped_from=ex.__class__.__name__) from ex LOG.debug("Getting remote event '%s' for resource: %s", name, function_resource) - event = lambda_test_event.get_event(name, function_resource) + event = lambda_test_event.get_event(name, function_resource)["json"] try: output_file.write(event) diff --git a/samcli/commands/remote/test_event/put/cli.py b/samcli/commands/remote/test_event/put/cli.py index df98670c356..ebca56d3021 100644 --- a/samcli/commands/remote/test_event/put/cli.py +++ b/samcli/commands/remote/test_event/put/cli.py @@ -11,6 +11,7 @@ from samcli.cli.cli_config_file import ConfigProvider, configuration_option from samcli.cli.context import Context from samcli.cli.main import aws_creds_options, common_options, pass_context, print_cmdline_args +from samcli.commands._utils.click_mutex import ClickMutex from samcli.commands._utils.command_exception_handler import command_exception_handler from samcli.commands.remote.exceptions import IllFormedEventData from samcli.commands.remote.test_event.put.core.command import RemoteTestEventPutCommand @@ -19,6 +20,7 @@ stack_name_or_resource_id_atleast_one_option_validation, ) from samcli.lib.telemetry.metric import track_command +from samcli.lib.utils.invocation_type import EVENT, REQUEST_RESPONSE from samcli.lib.utils.version_checker import check_newer_version from samcli.yamlhelper import yaml_parse @@ -56,6 +58,14 @@ "The option '--file' is required (You can provide '-' to read from stdin)" ), ) +@click.option( + "--invocation-type", + type=click.Choice([EVENT, REQUEST_RESPONSE]), + replace_help_option="--invocation-type INVOCATION_TYPE", + help="Lambda function invocation type." + + click.style(f"\n\nInvocation types: {[EVENT, REQUEST_RESPONSE]}", bold=True), + cls=ClickMutex, +) @click.option("--force", "-f", is_flag=True, help="Force saving the event even if it already exists") @click.argument("resource-id", required=False) @aws_creds_options @@ -72,6 +82,7 @@ def cli( resource_id: Optional[str], name: str, file: TextIOWrapper, + invocation_type: str, force: bool, config_file: str, config_env: str, @@ -84,6 +95,7 @@ def cli( resource_id, name, file, + invocation_type, force, ctx.region, ctx.profile, @@ -97,6 +109,7 @@ def do_cli( resource_id: Optional[str], name: str, file: TextIOWrapper, + invocation_type: str, force: bool, region: str, profile: str, @@ -147,7 +160,7 @@ def do_cli( data = yaml_parse(contents) event_data = json.dumps(data) LOG.debug("Creating remote event %s from resource: %s", name, function_resource) - lambda_test_event.create_event(name, function_resource, event_data, force=force) + lambda_test_event.create_event(name, function_resource, event_data, invocation_type, force=force) click.echo(f"Put remote event '{name}' completed successfully") except (ValueError, YAMLError, JSONDecodeError) as ex: raise IllFormedEventData(f"File {file.name} doesn't contain a valid JSON:\n {ex}") from ex diff --git a/samcli/commands/remote/test_event/put/core/options.py b/samcli/commands/remote/test_event/put/core/options.py index a428a7c16de..dff5f16f5de 100644 --- a/samcli/commands/remote/test_event/put/core/options.py +++ b/samcli/commands/remote/test_event/put/core/options.py @@ -18,7 +18,7 @@ # NOTE: The ordering of the option lists matter, they are the order # in which options will be displayed. -EVENT_OPTIONS: List[str] = ["name", "file", "force"] +EVENT_OPTIONS: List[str] = ["name", "file", "invocation_type", "force"] ALL_OPTIONS: List[str] = ( INFRASTRUCTURE_OPTION_NAMES diff --git a/samcli/lib/shared_test_events/lambda_shared_test_event.py b/samcli/lib/shared_test_events/lambda_shared_test_event.py index bb489a87b47..49fc0cf9063 100644 --- a/samcli/lib/shared_test_events/lambda_shared_test_event.py +++ b/samcli/lib/shared_test_events/lambda_shared_test_event.py @@ -3,7 +3,7 @@ import json import logging from json import JSONDecodeError -from typing import Any +from typing import Any, Optional import botocore @@ -17,6 +17,7 @@ ) from samcli.lib.schemas.schemas_api_caller import SchemasApiCaller from samcli.lib.utils.cloudformation import CloudFormationResourceSummary +from samcli.lib.utils.invocation_type import REQUEST_RESPONSE from samcli.lib.utils.resources import AWS_LAMBDA_FUNCTION LAMBDA_TEST_EVENT_REGISTRY = "lambda-testevent-schemas" @@ -142,7 +143,14 @@ def limit_versions(self, schema_name: str, registry_name: str = LAMBDA_TEST_EVEN ) self._api_caller.delete_version(registry_name, schema_name, version_to_delete) - def add_event_to_schema(self, schema: str, event: str, event_name: str, replace_if_exists: bool = False) -> str: + def add_event_to_schema( + self, + schema: str, + event: str, + event_name: str, + metadata: Optional[dict[str, str]], + replace_if_exists: bool = False, + ) -> str: """ Adds an event to a schema @@ -176,6 +184,8 @@ def add_event_to_schema(self, schema: str, event: str, event_name: str, replace_ schema_dict["components"]["examples"][event_name] = { "value": event_dict, } + if metadata: + schema_dict["components"]["examples"][event_name]["x-metadata"] = metadata schema = json.dumps(schema_dict) @@ -200,7 +210,7 @@ def get_event_from_schema(self, schema: str, event_name: str) -> Any: the name of the event to retrieve from the schema Returns ------- - The event data of the event "event_name" + The event data and metadata of the event "event_name" """ try: schema_dict = json.loads(schema) @@ -211,7 +221,7 @@ def get_event_from_schema(self, schema: str, event_name: str) -> Any: raise ResourceNotFound(f"Event {event_name} not found") # can use square brackets here since we know each of these subdicts exist - return existing_events[event_name]["value"] + return existing_events[event_name] except JSONDecodeError as ex: LOG.error("Error decoding schema when getting event %s", event_name) @@ -263,6 +273,7 @@ def create_event( event_name: str, function_resource: CloudFormationResourceSummary, event_data: str, + invocation_type: str = REQUEST_RESPONSE, force: bool = False, registry_name: str = LAMBDA_TEST_EVENT_REGISTRY, ) -> str: @@ -277,6 +288,8 @@ def create_event( The function where the event will be created event_data: str The JSON data of the event to be created + invocation_type: str + The Lambda invocation type of the event to be created registry_name: str The name of the registry that contains the schema """ @@ -287,16 +300,19 @@ def create_event( schema_name = self._get_schema_name(function_resource) original_schema = api_caller.get_schema(registry_name, schema_name) + metadata = {"invocationType": invocation_type} if original_schema: LOG.debug("Schema %s already exists, adding event %s", schema_name, event_name) self.limit_versions(schema_name, registry_name) - schema = self.add_event_to_schema(original_schema, event_data, event_name, replace_if_exists=force) + schema = self.add_event_to_schema( + original_schema, event_data, event_name, metadata, replace_if_exists=force + ) api_caller.update_schema(schema, registry_name, schema_name, OPEN_API_TYPE) else: LOG.debug("Schema %s does not already exist, creating new", schema_name) schema = api_caller.discover_schema(event_data, OPEN_API_TYPE) - schema = self.add_event_to_schema(schema, event_data, event_name) + schema = self.add_event_to_schema(schema, event_data, event_name, metadata) api_caller.create_schema(schema, registry_name, schema_name, OPEN_API_TYPE) return schema @@ -346,7 +362,7 @@ def get_event( event_name: str, function_resource: CloudFormationResourceSummary, registry_name: str = LAMBDA_TEST_EVENT_REGISTRY, - ) -> str: + ) -> Any: """ Returns a remote test event @@ -360,7 +376,7 @@ def get_event( The name of the registry that contains the schema Returns ------- - The JSON data of the event + The parsed JSON data and metadata of the event """ api_caller = self._api_caller @@ -377,7 +393,7 @@ def get_event( event = self.get_event_from_schema(schema, event_name) try: - return json.dumps(event) + return {"json": json.dumps(event["value"]), "metadata": event.get("x-metadata", {})} except JSONDecodeError as ex: LOG.error("Error parsing event %s from schema %s", event_name, schema_name) diff --git a/samcli/lib/utils/invocation_type.py b/samcli/lib/utils/invocation_type.py new file mode 100644 index 00000000000..9dc3c58cd64 --- /dev/null +++ b/samcli/lib/utils/invocation_type.py @@ -0,0 +1,6 @@ +""" +Enums for determining InvocationType of a Lambda function invoke. +""" + +EVENT = "Event" +REQUEST_RESPONSE = "RequestResponse" diff --git a/tests/unit/commands/remote/invoke/test_cli.py b/tests/unit/commands/remote/invoke/test_cli.py index e30b6a33924..36d7dbabd17 100644 --- a/tests/unit/commands/remote/invoke/test_cli.py +++ b/tests/unit/commands/remote/invoke/test_cli.py @@ -147,7 +147,7 @@ def test_remote_invoke_with_shared_test_event_command( context_mock = Mock() test_event_mock = Mock() - test_event_mock.get_event.return_value = "stuff" + test_event_mock.get_event.return_value = {"json": "stuff", "metadata": {}} fn_resource = Mock() fn_resource.resource_type = AWS_LAMBDA_FUNCTION context_mock.resource_summary = fn_resource @@ -191,6 +191,142 @@ def mock_tracker(name, value): # when track_event is called, append an equivale # Assert metric was emitted self.assertIn(["RemoteInvokeEventType", "remote_event"], tracked_events) + @patch("samcli.lib.remote_invoke.remote_invoke_executors.RemoteInvokeExecutionInfo") + @patch("samcli.lib.utils.boto_utils.get_boto_client_provider_with_config") + @patch("samcli.lib.utils.boto_utils.get_boto_resource_provider_with_config") + @patch("samcli.commands.remote.remote_invoke_context.RemoteInvokeContext") + @patch("samcli.lib.telemetry.event.EventTracker.track_event") + def test_remote_invoke_with_shared_test_event_metadata_command( + self, + mock_track_event, + mock_remote_invoke_context, + patched_get_boto_resource_provider_with_config, + patched_get_boto_client_provider_with_config, + patched_remote_invoke_execution_info, + ): + given_client_provider = Mock() + patched_get_boto_client_provider_with_config.return_value = given_client_provider + + given_resource_provider = Mock() + patched_get_boto_resource_provider_with_config.return_value = given_resource_provider + + given_remote_invoke_execution_info = Mock() + patched_remote_invoke_execution_info.return_value = given_remote_invoke_execution_info + + context_mock = Mock() + test_event_mock = Mock() + test_event_mock.get_event.return_value = {"json": "stuff", "metadata": {"invocationType": "Event"}} + fn_resource = Mock() + fn_resource.resource_type = AWS_LAMBDA_FUNCTION + context_mock.resource_summary = fn_resource + context_mock.get_lambda_shared_test_event_provider.return_value = test_event_mock + mock_remote_invoke_context.return_value.__enter__.return_value = context_mock + + given_remote_invoke_result = Mock() + given_remote_invoke_result.is_succeeded.return_value = True + given_remote_invoke_result.log_output = "log_output" + context_mock.run.return_value = given_remote_invoke_result + + tracked_events = [] + + def mock_tracker(name, value): # when track_event is called, append an equivalent event to our list + tracked_events.append([name, value]) + + mock_track_event.side_effect = mock_tracker + + do_cli( + stack_name=self.stack_name, + resource_id=self.resource_id, + event=None, + event_file=None, + parameter={}, + output=RemoteInvokeOutputFormat.TEXT, + test_event_name="event1", + region=self.region, + profile=self.profile, + config_file=self.config_file, + config_env=self.config_env, + ) + + test_event_mock.get_event.assert_called_with("event1", fn_resource) + patched_remote_invoke_execution_info.assert_called_with( + payload="stuff", + payload_file=None, + parameters={"InvocationType": "Event"}, + output_format=RemoteInvokeOutputFormat.TEXT, + ) + context_mock.run.assert_called_with(remote_invoke_input=given_remote_invoke_execution_info) + # Assert metric was emitted + self.assertIn(["RemoteInvokeEventType", "remote_event"], tracked_events) + + @patch("samcli.lib.remote_invoke.remote_invoke_executors.RemoteInvokeExecutionInfo") + @patch("samcli.lib.utils.boto_utils.get_boto_client_provider_with_config") + @patch("samcli.lib.utils.boto_utils.get_boto_resource_provider_with_config") + @patch("samcli.commands.remote.remote_invoke_context.RemoteInvokeContext") + @patch("samcli.lib.telemetry.event.EventTracker.track_event") + def test_remote_invoke_with_shared_test_event_metadata_and_cli_overrides_command( + self, + mock_track_event, + mock_remote_invoke_context, + patched_get_boto_resource_provider_with_config, + patched_get_boto_client_provider_with_config, + patched_remote_invoke_execution_info, + ): + given_client_provider = Mock() + patched_get_boto_client_provider_with_config.return_value = given_client_provider + + given_resource_provider = Mock() + patched_get_boto_resource_provider_with_config.return_value = given_resource_provider + + given_remote_invoke_execution_info = Mock() + patched_remote_invoke_execution_info.return_value = given_remote_invoke_execution_info + + context_mock = Mock() + test_event_mock = Mock() + test_event_mock.get_event.return_value = {"json": "stuff", "metadata": {"invocationType": "Event"}} + fn_resource = Mock() + fn_resource.resource_type = AWS_LAMBDA_FUNCTION + context_mock.resource_summary = fn_resource + context_mock.get_lambda_shared_test_event_provider.return_value = test_event_mock + mock_remote_invoke_context.return_value.__enter__.return_value = context_mock + + given_remote_invoke_result = Mock() + given_remote_invoke_result.is_succeeded.return_value = True + given_remote_invoke_result.log_output = "log_output" + context_mock.run.return_value = given_remote_invoke_result + + tracked_events = [] + + def mock_tracker(name, value): # when track_event is called, append an equivalent event to our list + tracked_events.append([name, value]) + + mock_track_event.side_effect = mock_tracker + + do_cli( + stack_name=self.stack_name, + resource_id=self.resource_id, + event=None, + event_file=None, + parameter={"InvocationType": "RequestResponse"}, + output=RemoteInvokeOutputFormat.TEXT, + test_event_name="event1", + region=self.region, + profile=self.profile, + config_file=self.config_file, + config_env=self.config_env, + ) + + test_event_mock.get_event.assert_called_with("event1", fn_resource) + patched_remote_invoke_execution_info.assert_called_with( + payload="stuff", + payload_file=None, + parameters={"InvocationType": "RequestResponse"}, + output_format=RemoteInvokeOutputFormat.TEXT, + ) + context_mock.run.assert_called_with(remote_invoke_input=given_remote_invoke_execution_info) + # Assert metric was emitted + self.assertIn(["RemoteInvokeEventType", "remote_event"], tracked_events) + @patch("samcli.lib.remote_invoke.remote_invoke_executors.RemoteInvokeExecutionInfo") @patch("samcli.lib.utils.boto_utils.get_boto_client_provider_with_config") @patch("samcli.lib.utils.boto_utils.get_boto_resource_provider_with_config") diff --git a/tests/unit/commands/remote/test_event/test_cli.py b/tests/unit/commands/remote/test_event/test_cli.py index 5fd4494d417..a2f4f909cfb 100644 --- a/tests/unit/commands/remote/test_event/test_cli.py +++ b/tests/unit/commands/remote/test_event/test_cli.py @@ -130,7 +130,7 @@ def test_remote_test_event_get_command_file( context_mock.get_lambda_shared_test_event_provider.return_value = test_event_mock mock_remote_invoke_context.return_value.__enter__.return_value = context_mock - test_event_mock.get_event.return_value = "placeholderstring" + test_event_mock.get_event.return_value = {"json": "placeholderstring", "metadata": {}} function_resource = Mock() context_mock.resource_summary = function_resource @@ -215,7 +215,7 @@ def test_remote_test_event_get_file_error( context_mock.get_lambda_shared_test_event_provider.return_value = test_event_mock mock_remote_invoke_context.return_value.__enter__.return_value = context_mock - test_event_mock.get_event.return_value = "placeholderstring" + test_event_mock.get_event.return_value = {"json": "placeholderstring", "metadata": {}} context_mock.resource_summary = Mock() @@ -265,6 +265,7 @@ def test_remote_test_event_put_command( resource_id=self.resource_id, name=self.name, file=Mock(), + invocation_type="RequestResponse", force=False, region=self.region, profile=self.profile, @@ -279,7 +280,9 @@ def test_remote_test_event_put_command( resource_id=self.resource_id, ) - test_event_mock.create_event.assert_called_with(self.name, function_resource, '{"foo": "bar"}', force=False) + test_event_mock.create_event.assert_called_with( + self.name, function_resource, '{"foo": "bar"}', "RequestResponse", force=False + ) @parameterized.expand( [ @@ -315,6 +318,7 @@ def test_raise_user_exception_put_not_successfull( resource_id="mock-resource-id", name="event", file="foo", + invocation_type="RequestResponse", force=False, region=self.region, profile=self.profile, @@ -351,6 +355,7 @@ def test_put_fails_when_empty( resource_id="mock-resource-id", name="event", file=empty_file, + invocation_type="RequestResponse", force=False, region=self.region, profile=self.profile, @@ -387,6 +392,7 @@ def test_put_fails_when_json_error( resource_id="mock-resource-id", name="event", file=empty_file, + invocation_type="RequestResponse", force=False, region=self.region, profile=self.profile, diff --git a/tests/unit/lib/shared_test_events/test_lambda_shared_test_event.py b/tests/unit/lib/shared_test_events/test_lambda_shared_test_event.py index 5e453a49286..322c0ffb8fd 100644 --- a/tests/unit/lib/shared_test_events/test_lambda_shared_test_event.py +++ b/tests/unit/lib/shared_test_events/test_lambda_shared_test_event.py @@ -198,7 +198,7 @@ def test_create_event_new_schema_success(self): self.client.get_discovered_schema.assert_called_once_with(Events=['{"key": "number1"}'], Type="OpenApi3") self.client.create_schema.assert_called_once_with( - Content='{"openapi": "3.0.0", "info": {"version": "1.0.0", "title": "Event"}, "paths": {}, "components": {"schemas": {"Event": {"type": "object", "required": ["key"], "properties": {"key": {"type": "string"}}}}, "examples": {"test1": {"value": {"key": "number1"}}}}}', + Content='{"openapi": "3.0.0", "info": {"version": "1.0.0", "title": "Event"}, "paths": {}, "components": {"schemas": {"Event": {"type": "object", "required": ["key"], "properties": {"key": {"type": "string"}}}}, "examples": {"test1": {"value": {"key": "number1"}, "x-metadata": {"invocationType": "RequestResponse"}}}}}', RegistryName="lambda-testevent-schemas", SchemaName="_MyFunction-schema", Type="OpenApi3", @@ -223,7 +223,7 @@ def test_create_event_schema_exists_success(self, _list_schema_versions_mock): lambda_test_event.create_event("test2", self._cfn_resource("MyFunction"), '{"key": "number2"}') self.client.update_schema.assert_called_once_with( - Content='{"openapi": "3.0.0", "info": {"version": "1.0.0", "title": "Event"}, "paths": {}, "components": {"schemas": {"Event": {"type": "object", "required": ["key"], "properties": {"key": {"type": "string"}}}}, "examples": {"test1": {"value": {"key": "number1"}}, "test2": {"value": {"key": "number2"}}}}}', + Content='{"openapi": "3.0.0", "info": {"version": "1.0.0", "title": "Event"}, "paths": {}, "components": {"schemas": {"Event": {"type": "object", "required": ["key"], "properties": {"key": {"type": "string"}}}}, "examples": {"test1": {"value": {"key": "number1"}}, "test2": {"value": {"key": "number2"}, "x-metadata": {"invocationType": "RequestResponse"}}}}}', RegistryName="lambda-testevent-schemas", SchemaName="_MyFunction-schema", Type="OpenApi3", @@ -288,6 +288,31 @@ def test_create_not_available_error(self): ) self.assertEqual(str(ctx.exception), msg) + @patch.object(SchemasApiCaller, "list_schema_versions", return_value=["1"]) + def test_create_with_metadata(self, list_schema_versions_mock): + lambda_test_event = LambdaSharedTestEvent(self.schemas_api_caller, self.lambda_client) + self.client.describe_registry.return_value = {"registry": "someRegistry"} + + self.client.describe_schema.return_value = { + "SchemaArn": "", + "Tags": {}, + "LastModified": "2019-11-25T20:33:14Z", + "Content": '{"openapi":"3.0.0","info":{"version":"1.0.0","title":"Event"},"paths":{},"components":{"schemas":{"Event":{"type":"object","required":["key"],"properties":{"key":{"type":"string"}}}},"examples":{"test1":{"value":{"key":"number1"}}}}}', + "VersionCreatedDate": "2019-11-25T20:33:14Z", + "SchemaName": "aws.ssm@ParameterStoreChange", + "Type": "OpenApi3", + "SchemaVersion": "1", + } + + lambda_test_event.create_event("test2", self._cfn_resource("MyFunction"), '{"key": "number2"}', "Event") + + self.client.update_schema.assert_called_once_with( + Content='{"openapi": "3.0.0", "info": {"version": "1.0.0", "title": "Event"}, "paths": {}, "components": {"schemas": {"Event": {"type": "object", "required": ["key"], "properties": {"key": {"type": "string"}}}}, "examples": {"test1": {"value": {"key": "number1"}}, "test2": {"value": {"key": "number2"}, "x-metadata": {"invocationType": "Event"}}}}}', + RegistryName="lambda-testevent-schemas", + SchemaName="_MyFunction-schema", + Type="OpenApi3", + ) + def test_get_event_success(self): lambda_test_event = LambdaSharedTestEvent(self.schemas_api_caller, self.lambda_client) self.client.describe_registry.return_value = {"registry": "someRegistry"} @@ -305,7 +330,8 @@ def test_get_event_success(self): event = lambda_test_event.get_event("test1", self._cfn_resource("MyFunction")) - self.assertEqual(event, '{"key": "number1"}') + self.assertEqual(event["json"], '{"key": "number1"}') + self.assertEqual(event["metadata"], {}) def test_get_event_no_registry(self): lambda_test_event = LambdaSharedTestEvent(self.schemas_api_caller, self.lambda_client) @@ -371,6 +397,26 @@ def test_get_not_available_error(self): ) self.assertEqual(str(ctx.exception), msg) + def test_get_with_metadata(self): + lambda_test_event = LambdaSharedTestEvent(self.schemas_api_caller, self.lambda_client) + self.client.describe_registry.return_value = {"registry": "someRegistry"} + + self.client.describe_schema.return_value = { + "SchemaArn": "", + "Tags": {}, + "LastModified": "2019-11-25T20:33:14Z", + "Content": '{"openapi":"3.0.0","info":{"version":"1.0.0","title":"Event"},"paths":{},"components":{"schemas":{"Event":{"type":"object","required":["key"],"properties":{"key":{"type":"string"}}}},"examples":{"test1":{"value":{"key":"number1"},"x-metadata":{"invocationType":"Event"}}}}}', + "VersionCreatedDate": "2019-11-25T20:33:14Z", + "SchemaName": "aws.ssm@ParameterStoreChange", + "Type": "OpenApi3", + "SchemaVersion": "1", + } + + event = lambda_test_event.get_event("test1", self._cfn_resource("MyFunction")) + + self.assertEqual(event["json"], '{"key": "number1"}') + self.assertEqual(event["metadata"], {"invocationType": "Event"}) + @patch.object(SchemasApiCaller, "list_schema_versions", return_value=["1"]) def test_limit_version_under_cap(self, list_schema_versions_mock): lambda_test_event = LambdaSharedTestEvent(self.schemas_api_caller, self.lambda_client)