getmoto / moto

A library that allows you to easily mock out tests based on AWS infrastructure.

Home Page:http://docs.getmoto.org/en/latest/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Calling the "getSendStatistics()" function on the Java SES SDKv2 client throws a date format exception.

code-and-such opened this issue · comments

TLDR:

Calling the "getSendStatistics()" function using the Java SES SDKv2 client throws a date format exception.

The SDK expect the date to be an UTC date - that is, suffixed with 'Z', like 2024-04-29T11:53:35.987469Z. What it get is 2024-04-29T11:53:35.987469.

Expect behavior:

A response that can be de-serialized/parsed by the SES client successfully

Actual behavior:

An exception exception is thrown upon trying to parsing the response:

java.time.format.DateTimeParseException: Text '2024-04-29T12:02:57.370491' could not be parsed at index 26

Cause

The response returned from moto looks like this:

<GetSendStatisticsResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
    <GetSendStatisticsResult>
        <SendDataPoints>
            <member>
                <DeliveryAttempts>1</DeliveryAttempts>
                <Rejects>0</Rejects>
                <Bounces>0</Bounces>
                <Complaints>0</Complaints>
                <Timestamp>2024-04-29T11:53:35.987469</Timestamp>
            </member>
        </SendDataPoints>
    </GetSendStatisticsResult>
    <ResponseMetadata>
        <RequestId>3oohUOjkXc4TaVWi2oyivhwS0CPTFiEit4fJC7wOLCCFxnSRoPWw</RequestId>
    </ResponseMetadata>
</GetSendStatisticsResponse>

The SDK expect the date to be a Iso8601Date - which isn't. 2024-04-29T11:53:35.987469Z would have been acceptable, but without the UTC marker, Z, it all goes sideways.

"Full" Stacktrace

java.time.format.DateTimeParseException: Text '2024-04-29T12:19:14.993264' could not be parsed at index 26
	at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
	at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
	at software.amazon.awssdk.utils.DateUtils.parseInstant(DateUtils.java:190)
	at software.amazon.awssdk.utils.DateUtils.parseIso8601Date(DateUtils.java:98)
	at software.amazon.awssdk.protocols.core.StringToInstant.convert(StringToInstant.java:52)
	at software.amazon.awssdk.protocols.core.StringToInstant.convert(StringToInstant.java:32)
	at software.amazon.awssdk.protocols.query.internal.unmarshall.SimpleTypeQueryUnmarshaller.unmarshall(SimpleTypeQueryUnmarshaller.java:43)
	at software.amazon.awssdk.protocols.query.internal.unmarshall.QueryProtocolUnmarshaller.unmarshall(QueryProtocolUnmarshaller.java:139)
	at software.amazon.awssdk.protocols.query.internal.unmarshall.QueryProtocolUnmarshaller.lambda$static$1(QueryProtocolUnmarshaller.java:65)
	at software.amazon.awssdk.protocols.query.internal.unmarshall.ListQueryUnmarshaller.lambda$unmarshall$0(ListQueryUnmarshaller.java:37)

Investigation of what the client does:

The relevant classes in the SDK are

https://github.com/aws/aws-sdk-java-v2/blob/master/utils/src/main/java/software/amazon/awssdk/utils/DateUtils.java
https://github.com/aws/aws-sdk-java-v2/blob/master/core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/StringToInstant.java
https://github.com/aws/aws-sdk-java-v2/blob/master/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/SimpleTypeQueryMarshaller.java

The SDK will guess that the date is an Iso8601Date - which isn't, apparently. So why does it think that? Well, because that's the only thing the SDK handles by default it seems, as can be seen at

https://github.com/aws/aws-sdk-java-v2/blob/e4fb225dc46c86eff09b40b038ba21c02add6130/core/protocols/aws-query-protocol/src/main/java/software/amazon/awssdk/protocols/query/internal/marshall/SimpleTypeQueryMarshaller.java#L77

It will try the following formats before it throws the error

2011-12-03T10:15:30Z
2024-04-29T11:53:35.987469Z # I think it would accept fewer fraction digits too - the Java SDK ISO_INSTANCE parser implementation is a bit lengthy
2011-12-03T10:15:30+01:00

Versions:

Moto version: Moto 5.0.6 (Dockerized)
Java SES SDK version: 2.20.96
Java version: 11 (but I can see the behavior is same even in Java version 21)

Additional information:

  • The relevant date parsing code is shared among the AWS Java SDK v2 clients. My guess is that any place that returns dates in this format will flip the cart over.

  • The user agent string sent is aws-sdk-java/2.20.96 <loadsa stuff about my machine>. It is conceivable that AWS adapts the response based on this, and that might could for why it apparently works for other clients. I haven't tried this with the v1 SDK, but I can, if requested.

Hi @code-and-such, thanks for letting us know. I've opened a PR with a fix.

Most of our tests are in Python, and that SDK is much more forgiving when it comes to parsing dates. That's why we don't always catch errors like this.
The PR that I've just opened also tests this scenario with the Java SDK, to prevent it from happening again.