【问题标题】:Testing my AWS Lambda function with a fake S3Event使用假 S3Event 测试我的 AWS Lambda 函数
【发布时间】:2021-04-29 19:29:05
【问题描述】:

我正在为从 S3 触发的 AWS Lambda 实施 Java 8 包,获取一些文件数据并放入另一个 S3 存储桶。

这是我目前的Handler

public class Handler implements RequestHandler<S3Event, Void> {
    private static final String TARGET_BUCKET = "some-bucket";

    private AmazonS3Client s3Client = new AmazonS3Client(new DefaultAWSCredentialsProviderChain());
    private Runner runner = new Runner(s3Client, TARGET_BUCKET);

    @Override
    public Void handleRequest(S3Event s3Event, Context context) {
        runner.run(s3Event, context);

        return null;
    }
}

我已将业务逻辑移至我的Runner 类,以便我可以正确测试它(遵循AWS Lambda best practices white paper)。

但是,我很难知道如何通过伪造的 S3Event 来测试我的 run 函数。

我目前的测试是:

@Test
public void putsDataIntoS3() throws IOException {
    runner.run(new ObjectMapper().readValue(loadJsonFromFile("s3-event.json"), S3Event.class), context);

    assertTrue(true);
}

loadJsonFromFile 获取具有我要传递的文件名的资源,将其转换为输入流,然后转换为 String

但是,这会导致错误:

com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.amazonaws.services.lambda.runtime.events.S3Event]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)

所以我的问题是,如何通过传递假的 S3Event JSON 来正确测试我的 run 函数?

这些是我正在使用的与 aws 相关的依赖项:

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-lambda-java-core</artifactId>
    <version>1.1.0</version>
</dependency>
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-lambda-java-events</artifactId>
    <version>2.2.2</version>
</dependency>
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-s3</artifactId>
    <version>1.11.455</version>
</dependency>

编辑:

我可以像这样使用S3Event.parseJson 函数: 我也见过parseJson函数,可以这样使用:

@Test
public void putsFilteredDataIntoS3() throws IOException {
    runner.run(new S3Event(S3Event.parseJson(loadJsonFromFile("s3-event.json")).getRecords()), context);

    assertTrue(true);
}

但是这样做是最佳实践吗?

【问题讨论】:

  • 您使用的是什么版本的 aws-lambda 库?
  • 可以显示s3-event.json的内容吗?
  • 在原问题中添加了aws相关的库
  • s3-event.json 基本上是 PUT 示例的副本:docs.aws.amazon.com/AmazonS3/latest/dev/…
  • @Sir.Hedgehog 因为泛型

标签: java amazon-web-services aws-lambda


【解决方案1】:

您可以使用 Mockito 库并尝试模拟此 S3Event

从 JSON 创建S3Event 的另一个选项:

S3EventNotification notification = S3EventNotification.parseJson(loadJsonFromFile("s3-event.json"));
S3Event event = new S3Event(notification.getRecords());

编辑: 第三种选择是将您的aws-lambda-java-events 更新到版本2.2.4,他们在其中为S3Event 添加了默认构造函数,因此您可以像这样反序列化它:

objectMapper.readValue(loadJsonFromFile("s3-event.json"), S3Event.class)

【讨论】:

  • 啊,实际上我刚刚意识到我也可以做到这一点(在您编辑此问题的同时编辑了我的问题)!不过,我仍然有兴趣看看是否还有其他方法。
  • @pavlos163 为您的问题找到了另一种解决方案
【解决方案2】:

如果您使用的是 AWS 开发工具包的版本 2,最简单的方法是使用亚马逊内部使用的反序列化器:

AWS Lambda Java 运行时序列化

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-lambda-java-serialization</artifactId>
    <version>1.0.0</version>
</dependency>

它的工作原理如下:

PojoSerializer<S3Event> s3EventSerializer = LambdaEventSerializers.serializerFor(S3Event.class, ClassLoader.getSystemClassLoader());
S3Event event = s3EventSerializer.fromJson(inputStream);

有一件重要的事情需要了解(AWS SDK 版本 2 与版本 1)

如果您的 JSON 存在问题(不兼容的字段值或 JodaTime 库不在类路径中),序列化程序将不执行任何操作并激活 AWS SDK 1 回退。最后你会得到这样的错误:

java.lang.ClassNotFoundException: com.amazonaws.services.s3.event.S3EventNotification$S3EventNotificationRecord.

此消息错误。 AWS 解串器与版本 2 和版本 1 完美配合。库本身不依赖于 SDK(无论是 1 还是 2)。很可能您需要检查 JSON。

【讨论】:

    【解决方案3】:

    我一直在 S3Event 和 S3NotificationEvent 的两个包之间遇到问题。

    由于

    ,我无法将 json 解析为 com.amazonaws.services.lambda.runtime.events.S3EventNotification

    https://github.com/aws/aws-lambda-java-libs/issues/151

    阅读 JSON 后,我得到了 com.amazonaws.services.s3.event.S3EventNotification 但是 FunctionHandler 需要来自的 S3Event com.amazonaws.services.lambda.runtime.events.S3Event.

    我做不到S3Event(notification.records)

    所以我必须编写自己的方法来转换类

        fun test() {
            val fileContent = this::class.java.classLoader.getResource("s3-event.json").readText()
            val s3NotificationEvent = ObjectMapper().registerKotlinModule().readValue(fileContent, S3EventNotification::class.java)
            val s3Event = S3Event(
                s3NotificationEvent.records.map {
                    it.toRuntimeS3NotificationRecord()
                }
            )
        )
    
    fun S3EventNotification.S3EventNotificationRecord.toRuntimeS3NotificationRecord(): com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.S3EventNotificationRecord {
    return com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.S3EventNotificationRecord(
        awsRegion, eventName, eventSource,
        eventTime.toString(), eventVersion,
        com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.RequestParametersEntity(requestParameters.sourceIPAddress),
        com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.ResponseElementsEntity(responseElements.getxAmzId2(), responseElements.getxAmzRequestId()),
        com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.S3Entity(
            s3.configurationId,
            com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.S3BucketEntity(
                s3.bucket.name,
                com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.UserIdentityEntity(s3.bucket.ownerIdentity.principalId),
                s3.bucket.arn
            ),
            com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.S3ObjectEntity(s3.`object`.key, s3.`object`.sizeAsLong, s3.`object`.geteTag(), s3.`object`.versionId, s3.`object`.sequencer),
            s3.s3SchemaVersion
        ),
        com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification.UserIdentityEntity(userIdentity.principalId)
    )
    

    }

    【讨论】:

      猜你喜欢
      • 2019-05-31
      • 1970-01-01
      • 1970-01-01
      • 2018-07-02
      • 1970-01-01
      • 1970-01-01
      • 2017-09-22
      • 2019-12-06
      • 1970-01-01
      相关资源
      最近更新 更多