我正在为从S3触发,获取一些文件数据并放入另一个S3存储桶的AWS Lambda实现Java 8程序包。
这是我当前的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?)
所以我的问题是,如何通过传递伪造的run
JSON来正确测试S3Event
函数?
这些是我正在使用的与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);
}
但这是最佳做法吗?
答案 0 :(得分:3)
您可以使用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)
答案 1 :(得分:1)
如果您使用的是 AWS SDK 的第 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。
答案 2 :(得分:0)
我一直在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)
)
}