Add serialization round-trip tests for event types#598
Open
darklight3it wants to merge 15 commits intomainfrom
Open
Add serialization round-trip tests for event types#598darklight3it wants to merge 15 commits intomainfrom
darklight3it wants to merge 15 commits intomainfrom
Conversation
added 12 commits
March 24, 2026 11:43
in the serialization package.
…eMQ serialization test fixtures
Add JSON test fixtures and round-trip test cases for CognitoEvent, DynamodbTimeWindowEvent, IoTButtonEvent, and KinesisTimeWindowEvent. These were the only events registered in LambdaEventSerializers SUPPORTED_EVENTS that lacked test fixtures. Fixtures based on official AWS Lambda documentation examples. Time window event fixtures use round-trip-safe date formats to avoid coercion issues. Coverage: 32 passing + 2 known failures (34 total, up from 30).
Add UnregisteredEventSerializationRoundTripTest covering events not in LambdaEventSerializers.SUPPORTED_EVENTS: 10 Cognito UserPool triggers, 5 Kinesis Analytics events, 2 API Gateway V2 WebSocket, 2 AppSync, 1 S3 Batch, and 1 TimeWindow response. S3ObjectLambdaEvent is a known failure (Lombok xAmzRequestId naming issue). Split SerializationRoundTripTest into registered (34 tests) and unregistered (22 tests) for clarity. Total: 56 tests, 53 passing, 3 known failures.
Add ResponseEventSerializationRoundTripTest covering all 11 response event types in aws-lambda-java-events. 9 pass cleanly, 2 are known failures (IamPolicyResponse, IamPolicyResponseV1 — getPolicyDocument() returns Map<String,Object> instead of the PolicyDocument POJO, making round-trip impossible by design since these are serialize-only types). Also update SerializationRoundTripTest comment for APIGatewayV2CustomAuthorizerEvent to clarify the date format change is a lossy transformation, not a bug. Total: 69 tests (34 registered + 22 unregistered + 11 response + 2 LambdaEventAssertTest), all green. Coverage now 66/68 event classes (97%).
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #598 +/- ##
=========================================
Coverage 65.38% 65.38%
Complexity 211 211
=========================================
Files 34 34
Lines 988 988
Branches 142 142
=========================================
Hits 646 646
Misses 290 290
Partials 52 52 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue #, if available:
Related to #594
Description of changes:
Add a serialization round-trip test that catches data loss and non-idempotent serialization across the events library. Previously,
EventLoaderTestcovered 27 event types with field-by-field assertions after a single deserialization pass. The new round-trip tests cover 66 event types (61 passing + 5 known failures), bringing coverage from ~40% to ~97% of the 68 classes inaws-lambda-java-events.How the test works
LambdaEventAssert.assertSerializationRoundTripperforms two consecutive round-trips (JSON → POJO → JSON → POJO → JSON) and compares the original JSON tree against the final output. Explicit nulls are stripped from the original since the serializer usesInclude.NON_NULL. AJsonNodeUtilshelper produces a structured diff listing every path that changed.Two passes catch both silently dropped fields and unstable serialization (output that changes across round-trips).
The test is split into three parameterized classes:
SerializationRoundTripTest(registered events),UnregisteredEventSerializationRoundTripTest(unregistered input events), andResponseEventSerializationRoundTripTest(response types). Each haspassingCases()for events that survive the round-trip cleanly, andknownFailureCases()for events expected to fail (wrapped inassertThrows). If a known failure suddenly passes, the test fails with a message to move it topassingCases().Why this approach
Field-by-field assertions in
EventLoaderTestonly verify the fields the test author remembered to check. The round-trip approach is exhaustive: any field present in the JSON fixture that gets lost or mutated during serialization is caught automatically. This kind of broad tests are the ones needed when updating jackson.Fixture corrections (false negatives in existing fixtures)
Several existing JSON fixtures contained fields that the event models silently drop during deserialization. These were false negatives — the fixtures looked complete but the data was being lost without any test catching it. Fixed by removing the unsupported fields from fixtures so the round-trip test has a clean baseline:
APIGatewayProxyRequestEventrequestContext.identity.clientCertRequestIdentityhas noclientCertfieldAPIGatewayV2HTTPEventrequestContext.authenticationRequestContexthas noauthenticationfieldCloudFrontEventrequest.querystring(as string)Map<String, List<String>>, notStringConnectEventcontactData.MediaStreamsContactDatahas nomediaStreamsfieldS3Events3.object.urlDecodedKey,s3.object.versionIdS3EventNotificationbut missing fromS3ObjectEntityActiveMQEventdestination.physicalname"physicalname"vs gettergetPhysicalName()— no@JsonPropertymappingEvents requiring separate round-trip fixtures
Some events needed dedicated
_roundtrip.jsonfixtures because the original fixtures contain values that Jackson leniently coerces during deserialization (e.g., numbers to strings), making the output structurally different from the input:DynamodbEventdynamo_event_roundtrip.jsonapproximateCreationDateTimeepoch seconds →DateformattingKinesisEventkinesis_event_roundtrip.jsonapproximateArrivalTimestampepoch seconds →DateformattingKafkaEventkafka_event_roundtrip.jsonMap<String, String>coerced to stringsLexEventlex_event_roundtrip.jsonslotstyped asMap<String, String>— numeric"Nights"coercedMSKFirehoseEventmsk_firehose_event_roundtrip.jsonRabbitMQEventrabbitmq_event_roundtrip.jsonexpiration(String→int),timestamp(long→formatted string)Known failures (3 events)
These five events fail the round-trip and are captured in
knownFailureCases():APIGatewayV2CustomAuthorizerEvent—getTime()parses"12/Mar/2020:19:03:58 +0000"into a JodaDateTimevia a custom formatter. Jackson serializes it as ISO-8601, which the formatter can't parse back on the second round-trip. Thetimefield is effectively mandatory (getTime()throws NPE if null), and the date format change is inherent to how the serialization works — not a bug, just a lossy transformation that prevents a clean round-trip.ActiveMQEvent(bug) —Destination.physicalName(camelCase) vs JSON"physicalname"(lowercase). SinceACCEPT_CASE_INSENSITIVE_PROPERTIESis disabled inJacksonFactory, the field is silently dropped during deserialization. Fix: add a mixin with@JsonProperty("physicalname").S3ObjectLambdaEvent(bug) — Lombok generatesgetXAmzRequestId()for fieldxAmzRequestId. WithUSE_STD_BEAN_NAMING, Jackson derives the property name as"XAmzRequestId"(capital X), so the original"xAmzRequestId"key is silently dropped during deserialization. Fix: add@JsonProperty("xAmzRequestId")on the field or getter.Target (OCI, Managed Runtime, both):
Both
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.