Skip to content

Add serialization round-trip tests for event types - #598

Merged
darklight3it merged 18 commits into
mainfrom
dmelfi/improve-serialization-testing
Mar 30, 2026
Merged

Add serialization round-trip tests for event types#598
darklight3it merged 18 commits into
mainfrom
dmelfi/improve-serialization-testing

Conversation

@darklight3it

@darklight3itdarklight3it commented Mar 25, 2026

Copy link
Copy Markdown
Collaborator

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, EventLoaderTest covered 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 in aws-lambda-java-events.

How the test works

LambdaEventAssert.assertSerializationRoundTrip performs 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 uses Include.NON_NULL. A JsonNodeUtils helper 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), and ResponseEventSerializationRoundTripTest (response types). Each has passingCases() for events that survive the round-trip cleanly, and knownFailureCases() for events expected to fail (wrapped in assertThrows). If a known failure suddenly passes, the test fails with a message to move it to passingCases().

Why this approach

Field-by-field assertions in EventLoaderTest only 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:

EventMissing Field(s)Root Cause
APIGatewayProxyRequestEventrequestContext.identity.clientCertRequestIdentity has no clientCert field
APIGatewayV2HTTPEventrequestContext.authenticationRequestContext has no authentication field
CloudFrontEventrequest.querystring (as string)Model uses Map<String, List<String>>, not String
ConnectEventcontactData.MediaStreamsContactData has no mediaStreams field
S3Events3.object.urlDecodedKey, s3.object.versionIdFields exist in S3EventNotification but missing from S3ObjectEntity
ActiveMQEventdestination.physicalnameCase mismatch: JSON "physicalname" vs getter getPhysicalName() — no @JsonProperty mapping

Events requiring separate round-trip fixtures

Some events needed dedicated _roundtrip.json fixtures 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:

EventFixtureReason
DynamodbEventdynamo_event_roundtrip.jsonapproximateCreationDateTime epoch seconds → Date formatting
KinesisEventkinesis_event_roundtrip.jsonapproximateArrivalTimestamp epoch seconds → Date formatting
KafkaEventkafka_event_roundtrip.jsonNumeric values in Map<String, String> coerced to strings
LexEventlex_event_roundtrip.jsonslots typed as Map<String, String> — numeric "Nights" coerced
MSKFirehoseEventmsk_firehose_event_roundtrip.jsonNumeric metadata values coerced to strings
RabbitMQEventrabbitmq_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():

  1. APIGatewayV2CustomAuthorizerEventgetTime() parses "12/Mar/2020:19:03:58 +0000" into a Joda DateTime via a custom formatter. Jackson serializes it as ISO-8601, which the formatter can't parse back on the second round-trip. The time field 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.

  2. ActiveMQEvent (bug)Destination.physicalName (camelCase) vs JSON "physicalname" (lowercase). Since ACCEPT_CASE_INSENSITIVE_PROPERTIES is disabled in JacksonFactory, the field is silently dropped during deserialization. Fix: add a mixin with @JsonProperty("physicalname").

  3. S3ObjectLambdaEvent (bug) — Lombok generates getXAmzRequestId() for field xAmzRequestId. With USE_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.

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

codecovBot commented Mar 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 65.38%. Comparing base (09c4b4e) to head (bb000e3).
⚠️ Report is 1 commits behind head on main.

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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@darklight3itdarklight3it self-assigned this Mar 25, 2026
@darklight3it
darklight3it marked this pull request as ready for review March 25, 2026 13:12
@darklight3it
darklight3it marked this pull request as draft March 25, 2026 13:27
@darklight3it
darklight3it marked this pull request as ready for review March 25, 2026 13:35
@darklight3it
darklight3itforce-pushed the dmelfi/improve-serialization-testing branch from 5a3c0b5 to bb000e3CompareMarch 27, 2026 15:16
@darklight3it
darklight3it merged commit 3e23521 into mainMar 30, 2026
10 checks passed
@darklight3it
darklight3it deleted the dmelfi/improve-serialization-testing branch April 20, 2026 22:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@darklight3it@M-Elsaeed@rarepolz