diff --git a/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AbstractLambdaPollLoop.java b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AbstractLambdaPollLoop.java index 347f0b3d4c845..720e8d4f4526c 100644 --- a/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AbstractLambdaPollLoop.java +++ b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AbstractLambdaPollLoop.java @@ -14,7 +14,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.databind.ObjectWriter; import io.quarkus.runtime.Application; import io.quarkus.runtime.ShutdownContext; @@ -144,9 +143,9 @@ public void run() { protected abstract void processRequest(InputStream input, OutputStream output, AmazonLambdaContext context) throws Exception; - protected abstract ObjectReader getInputReader(); + protected abstract LambdaInputReader getInputReader(); - protected abstract ObjectWriter getOutputWriter(); + protected abstract LambdaOutputWriter getOutputWriter(); protected AmazonLambdaContext createContext(HttpURLConnection requestConnection) throws IOException { return new AmazonLambdaContext(requestConnection, cognitoIdReader, clientCtxReader); @@ -202,4 +201,4 @@ boolean abortGracefully(Exception ex) { return graceful; } -} \ No newline at end of file +} diff --git a/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/JacksonInputReader.java b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/JacksonInputReader.java new file mode 100644 index 0000000000000..e66a774548c7b --- /dev/null +++ b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/JacksonInputReader.java @@ -0,0 +1,19 @@ +package io.quarkus.amazon.lambda.runtime; + +import java.io.IOException; +import java.io.InputStream; + +import com.fasterxml.jackson.databind.ObjectReader; + +public class JacksonInputReader implements LambdaInputReader { + final private ObjectReader reader; + + public JacksonInputReader(ObjectReader reader) { + this.reader = reader; + } + + @Override + public Object readValue(InputStream is) throws IOException { + return reader.readValue(is); + } +} diff --git a/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/JacksonOutputWriter.java b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/JacksonOutputWriter.java new file mode 100644 index 0000000000000..d950a57f741cf --- /dev/null +++ b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/JacksonOutputWriter.java @@ -0,0 +1,19 @@ +package io.quarkus.amazon.lambda.runtime; + +import java.io.IOException; +import java.io.OutputStream; + +import com.fasterxml.jackson.databind.ObjectWriter; + +public class JacksonOutputWriter implements LambdaOutputWriter { + final private ObjectWriter writer; + + public JacksonOutputWriter(ObjectWriter writer) { + this.writer = writer; + } + + @Override + public void writeValue(OutputStream os, Object obj) throws IOException { + writer.writeValue(os, obj); + } +} diff --git a/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/LambdaInputReader.java b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/LambdaInputReader.java new file mode 100644 index 0000000000000..ff9574d608715 --- /dev/null +++ b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/LambdaInputReader.java @@ -0,0 +1,8 @@ +package io.quarkus.amazon.lambda.runtime; + +import java.io.IOException; +import java.io.InputStream; + +public interface LambdaInputReader { + T readValue(InputStream is) throws IOException; +} diff --git a/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/LambdaOutputWriter.java b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/LambdaOutputWriter.java new file mode 100644 index 0000000000000..d9de5be4e9ff0 --- /dev/null +++ b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/LambdaOutputWriter.java @@ -0,0 +1,8 @@ +package io.quarkus.amazon.lambda.runtime; + +import java.io.IOException; +import java.io.OutputStream; + +public interface LambdaOutputWriter { + void writeValue(OutputStream os, Object obj) throws IOException; +} diff --git a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java index 5374bf6c47943..959399a01eeb7 100644 --- a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java +++ b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java @@ -12,10 +12,10 @@ import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.RequestStreamHandler; +import com.amazonaws.services.lambda.runtime.events.S3Event; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.databind.ObjectWriter; +import io.quarkus.amazon.lambda.runtime.handlers.S3EventInputReader; import io.quarkus.arc.runtime.BeanContainer; import io.quarkus.runtime.ShutdownContext; import io.quarkus.runtime.annotations.Recorder; @@ -32,8 +32,8 @@ public class AmazonLambdaRecorder { private static Class> handlerClass; private static Class streamHandlerClass; private static BeanContainer beanContainer; - private static ObjectReader objectReader; - private static ObjectWriter objectWriter; + private static LambdaInputReader objectReader; + private static LambdaOutputWriter objectWriter; public void setStreamHandlerClass(Class handler, BeanContainer container) { streamHandlerClass = handler; @@ -45,8 +45,12 @@ public void setHandlerClass(Class> handler, BeanC beanContainer = container; ObjectMapper objectMapper = AmazonLambdaMapperRecorder.objectMapper; Method handlerMethod = discoverHandlerMethod(handlerClass); - objectReader = objectMapper.readerFor(handlerMethod.getParameterTypes()[0]); - objectWriter = objectMapper.writerFor(handlerMethod.getReturnType()); + if (handlerMethod.getParameterTypes()[0].equals(S3Event.class)) { + objectReader = new S3EventInputReader(objectMapper); + } else { + objectReader = new JacksonInputReader(objectMapper.readerFor(handlerMethod.getParameterTypes()[0])); + } + objectWriter = new JacksonOutputWriter(objectMapper.writerFor(handlerMethod.getReturnType())); } /** @@ -149,12 +153,12 @@ protected Object processRequest(Object input, AmazonLambdaContext context) throw } @Override - protected ObjectReader getInputReader() { + protected LambdaInputReader getInputReader() { return objectReader; } @Override - protected ObjectWriter getOutputWriter() { + protected LambdaOutputWriter getOutputWriter() { return objectWriter; } diff --git a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/handlers/JacksonUtil.java b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/handlers/JacksonUtil.java new file mode 100644 index 0000000000000..ef02659f069db --- /dev/null +++ b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/handlers/JacksonUtil.java @@ -0,0 +1,15 @@ +package io.quarkus.amazon.lambda.runtime.handlers; + +import com.fasterxml.jackson.databind.JsonNode; + +public class JacksonUtil { + public static String getText(String name, JsonNode node) { + JsonNode e = node.get(name); + return e == null ? null : e.asText(); + } + + public static Long getLong(String name, JsonNode node) { + JsonNode e = node.get(name); + return e == null ? null : e.asLong(); + } +} diff --git a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/handlers/S3EventInputReader.java b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/handlers/S3EventInputReader.java new file mode 100644 index 0000000000000..602c602259b44 --- /dev/null +++ b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/handlers/S3EventInputReader.java @@ -0,0 +1,97 @@ +package io.quarkus.amazon.lambda.runtime.handlers; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.amazonaws.services.lambda.runtime.events.S3Event; +import com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.quarkus.amazon.lambda.runtime.LambdaInputReader; + +public class S3EventInputReader implements LambdaInputReader { + final ObjectMapper mapper; + + public S3EventInputReader(ObjectMapper mapper) { + this.mapper = mapper; + } + + @Override + public S3Event readValue(InputStream is) throws IOException { + JsonNode json = mapper.readTree(is); + JsonNode records = json.get("Records"); + if (records == null || !records.isArray()) { + return new S3Event(Collections.EMPTY_LIST); + } + List list = new ArrayList<>(); + + for (int i = 0; i < records.size(); i++) { + JsonNode record = records.get(i); + String awsRegion = JacksonUtil.getText("awsRegion", record); + String eventName = JacksonUtil.getText("eventName", record); + String eventSource = JacksonUtil.getText("eventSource", record); + String eventTime = JacksonUtil.getText("eventTime", record); + String eventVersion = JacksonUtil.getText("eventVersion", record); + JsonNode params = record.get("requestParameters"); + S3EventNotification.RequestParametersEntity requestParameters = null; + if (params != null) { + requestParameters = new S3EventNotification.RequestParametersEntity( + JacksonUtil.getText("sourceIPAddress", params)); + } + JsonNode elems = record.get("responseElements"); + S3EventNotification.ResponseElementsEntity responseElements = null; + if (elems != null) { + String requestId = JacksonUtil.getText("x-amz-request-id", elems); + String id = JacksonUtil.getText("x-amz-id-2", elems); + responseElements = new S3EventNotification.ResponseElementsEntity(id, requestId); + } + JsonNode userIdentity = record.get("userIdentity"); + S3EventNotification.UserIdentityEntity userId = null; + if (userIdentity != null) { + String principalId = JacksonUtil.getText("principalId", userIdentity); + userId = new S3EventNotification.UserIdentityEntity(principalId); + } + + JsonNode s3 = record.get("s3"); + S3EventNotification.S3Entity s3Entity = null; + if (s3 != null) { + String configurationId = JacksonUtil.getText("configurationId", s3); + String schemaVersion = JacksonUtil.getText("s3SchemaVersion", s3); + JsonNode bucketNode = s3.get("bucket"); + S3EventNotification.S3BucketEntity bucket = null; + if (bucketNode != null) { + String name = JacksonUtil.getText("name", bucketNode); + JsonNode ownerIdentity = bucketNode.get("ownerIdentity"); + S3EventNotification.UserIdentityEntity owner = null; + if (ownerIdentity != null) { + String principalId = JacksonUtil.getText("principalId", ownerIdentity); + owner = new S3EventNotification.UserIdentityEntity(principalId); + } + String arn = JacksonUtil.getText("arn", bucketNode); + bucket = new S3EventNotification.S3BucketEntity(name, owner, arn); + } + JsonNode object = s3.get("object"); + S3EventNotification.S3ObjectEntity obj = null; + if (object != null) { + String key = JacksonUtil.getText("key", object); + Long size = JacksonUtil.getLong("size", object); + String eTag = JacksonUtil.getText("eTag", object); + String versionId = JacksonUtil.getText("versionId", object); + String sequencer = JacksonUtil.getText("sequencer", object); + obj = new S3EventNotification.S3ObjectEntity(key, size, eTag, versionId, sequencer); + } + s3Entity = new S3EventNotification.S3Entity(configurationId, bucket, obj, schemaVersion); + } + S3EventNotification.S3EventNotificationRecord r = new S3EventNotification.S3EventNotificationRecord(awsRegion, + eventName, eventSource, eventTime, + eventVersion, requestParameters, + responseElements, s3Entity, userId); + list.add(r); + } + return new S3Event(list); + } +} diff --git a/extensions/amazon-lambda/runtime/src/test/java/io/quarkus/amazon/lambda/runtime/S3EventTest.java b/extensions/amazon-lambda/runtime/src/test/java/io/quarkus/amazon/lambda/runtime/S3EventTest.java new file mode 100644 index 0000000000000..400759f43e959 --- /dev/null +++ b/extensions/amazon-lambda/runtime/src/test/java/io/quarkus/amazon/lambda/runtime/S3EventTest.java @@ -0,0 +1,85 @@ +package io.quarkus.amazon.lambda.runtime; + +import java.io.ByteArrayInputStream; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.amazonaws.services.lambda.runtime.events.S3Event; +import com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification; +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.quarkus.amazon.lambda.runtime.handlers.S3EventInputReader; + +public class S3EventTest { + + static String json = "{\n" + + " \"Records\":[\n" + + " {\n" + + " \"eventVersion\":\"2.0\",\n" + + " \"eventSource\":\"aws:s3\",\n" + + " \"awsRegion\":\"us-west-2\",\n" + + " \"eventTime\":\"1970-01-01T00:00:00.000Z\",\n" + + " \"eventName\":\"ObjectCreated:Put\",\n" + + " \"userIdentity\":{\n" + + " \"principalId\":\"AIDAJDPLRKLG7UEXAMPLE\"\n" + + " },\n" + + " \"requestParameters\":{\n" + + " \"sourceIPAddress\":\"127.0.0.1\"\n" + + " },\n" + + " \"responseElements\":{\n" + + " \"x-amz-request-id\":\"C3D13FE58DE4C810\",\n" + + " \"x-amz-id-2\":\"FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD\"\n" + + " },\n" + + " \"s3\":{\n" + + " \"s3SchemaVersion\":\"1.0\",\n" + + " \"configurationId\":\"testConfigRule\",\n" + + " \"bucket\":{\n" + + " \"name\":\"sourcebucket\",\n" + + " \"ownerIdentity\":{\n" + + " \"principalId\":\"A3NL1KOZZKExample\"\n" + + " },\n" + + " \"arn\":\"arn:aws:s3:::sourcebucket\"\n" + + " },\n" + + " \"object\":{\n" + + " \"key\":\"HappyFace.jpg\",\n" + + " \"size\":1024,\n" + + " \"eTag\":\"d41d8cd98f00b204e9800998ecf8427e\",\n" + + " \"versionId\":\"096fKKXTRTtl3on89fVO.nfljtsv6qko\"\n" + + " }\n" + + " }\n" + + " }\n" + + " ]\n" + + "}"; + + @Test + public void testParse() throws Exception { + ObjectMapper mapper = new ObjectMapper(); + S3EventInputReader reader = new S3EventInputReader(mapper); + ByteArrayInputStream is = new ByteArrayInputStream(json.getBytes()); + S3Event event = reader.readValue(is); + Assertions.assertEquals(1, event.getRecords().size()); + S3EventNotification.S3EventNotificationRecord record = event.getRecords().get(0); + Assertions.assertEquals("2.0", record.getEventVersion()); + Assertions.assertEquals("aws:s3", record.getEventSource()); + Assertions.assertEquals("us-west-2", record.getAwsRegion()); + Assertions.assertEquals("1970-01-01T00:00:00.000Z", record.getEventTime().toString()); + Assertions.assertEquals("ObjectCreated:Put", record.getEventName()); + Assertions.assertEquals("AIDAJDPLRKLG7UEXAMPLE", record.getUserIdentity().getPrincipalId()); + Assertions.assertEquals("127.0.0.1", record.getRequestParameters().getSourceIPAddress()); + Assertions.assertEquals("C3D13FE58DE4C810", record.getResponseElements().getxAmzRequestId()); + Assertions.assertEquals("FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD", + record.getResponseElements().getxAmzId2()); + + Assertions.assertEquals("1.0", record.getS3().getS3SchemaVersion()); + Assertions.assertEquals("testConfigRule", record.getS3().getConfigurationId()); + Assertions.assertEquals("sourcebucket", record.getS3().getBucket().getName()); + Assertions.assertEquals("arn:aws:s3:::sourcebucket", record.getS3().getBucket().getArn()); + Assertions.assertEquals("A3NL1KOZZKExample", record.getS3().getBucket().getOwnerIdentity().getPrincipalId()); + Assertions.assertEquals("HappyFace.jpg", record.getS3().getObject().getKey()); + Assertions.assertEquals(1024, record.getS3().getObject().getSizeAsLong()); + Assertions.assertEquals("d41d8cd98f00b204e9800998ecf8427e", record.getS3().getObject().geteTag()); + Assertions.assertEquals("096fKKXTRTtl3on89fVO.nfljtsv6qko", record.getS3().getObject().getVersionId()); + + } +} diff --git a/extensions/funqy/funqy-amazon-lambda/runtime/src/main/java/io/quarkus/funqy/lambda/FunqyLambdaBindingRecorder.java b/extensions/funqy/funqy-amazon-lambda/runtime/src/main/java/io/quarkus/funqy/lambda/FunqyLambdaBindingRecorder.java index 9e620c2fce2cd..fc746093d588e 100644 --- a/extensions/funqy/funqy-amazon-lambda/runtime/src/main/java/io/quarkus/funqy/lambda/FunqyLambdaBindingRecorder.java +++ b/extensions/funqy/funqy-amazon-lambda/runtime/src/main/java/io/quarkus/funqy/lambda/FunqyLambdaBindingRecorder.java @@ -14,6 +14,10 @@ import io.quarkus.amazon.lambda.runtime.AbstractLambdaPollLoop; import io.quarkus.amazon.lambda.runtime.AmazonLambdaContext; import io.quarkus.amazon.lambda.runtime.AmazonLambdaMapperRecorder; +import io.quarkus.amazon.lambda.runtime.JacksonInputReader; +import io.quarkus.amazon.lambda.runtime.JacksonOutputWriter; +import io.quarkus.amazon.lambda.runtime.LambdaInputReader; +import io.quarkus.amazon.lambda.runtime.LambdaOutputWriter; import io.quarkus.arc.ManagedContext; import io.quarkus.arc.runtime.BeanContainer; import io.quarkus.funqy.runtime.FunctionConstructor; @@ -34,8 +38,8 @@ public class FunqyLambdaBindingRecorder { private static FunctionInvoker invoker; private static BeanContainer beanContainer; - private static ObjectReader reader; - private static ObjectWriter writer; + private static LambdaInputReader reader; + private static LambdaOutputWriter writer; public void init(BeanContainer bc) { beanContainer = bc; @@ -69,10 +73,10 @@ public void chooseInvoker(FunqyConfig config) { invoker = FunctionRecorder.registry.invokers().iterator().next(); } if (invoker.hasInput()) { - reader = (ObjectReader) invoker.getBindingContext().get(ObjectReader.class.getName()); + reader = new JacksonInputReader((ObjectReader) invoker.getBindingContext().get(ObjectReader.class.getName())); } if (invoker.hasOutput()) { - writer = (ObjectWriter) invoker.getBindingContext().get(ObjectWriter.class.getName()); + writer = new JacksonOutputWriter((ObjectWriter) invoker.getBindingContext().get(ObjectWriter.class.getName())); } } @@ -111,12 +115,12 @@ protected Object processRequest(Object input, AmazonLambdaContext context) throw } @Override - protected ObjectReader getInputReader() { + protected LambdaInputReader getInputReader() { return reader; } @Override - protected ObjectWriter getOutputWriter() { + protected LambdaOutputWriter getOutputWriter() { return writer; } diff --git a/integration-tests/amazon-lambda-s3event/pom.xml b/integration-tests/amazon-lambda-s3event/pom.xml new file mode 100644 index 0000000000000..55544227e4692 --- /dev/null +++ b/integration-tests/amazon-lambda-s3event/pom.xml @@ -0,0 +1,120 @@ + + + + quarkus-integration-tests-parent + io.quarkus + 999-SNAPSHOT + + 4.0.0 + + quarkus-integration-test-amazon-lambda-s3event + Quarkus - Integration Tests - Amazon Lambda + Module that contains Amazon Lambda S3Event related tests + + + io.quarkus + quarkus-amazon-lambda + + + + + org.junit.jupiter + junit-jupiter + + + io.quarkus + quarkus-junit5 + test + + + io.quarkus + quarkus-test-amazon-lambda + test + + + + + io.quarkus + quarkus-amazon-lambda-deployment + ${project.version} + pom + test + + + * + * + + + + + + + + + src/main/resources + true + + + + + io.quarkus + quarkus-maven-plugin + + + + build + + + + + + + + + + native-image + + + native + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${native.surefire.skip} + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + integration-test + verify + + + + + ${project.build.directory}/${project.build.finalName}-runner + + + + + + + + + + native + + + + + + diff --git a/integration-tests/amazon-lambda-s3event/src/main/java/io/quarkus/it/amazon/lambda/MyS3.java b/integration-tests/amazon-lambda-s3event/src/main/java/io/quarkus/it/amazon/lambda/MyS3.java new file mode 100644 index 0000000000000..b152b94bc26b6 --- /dev/null +++ b/integration-tests/amazon-lambda-s3event/src/main/java/io/quarkus/it/amazon/lambda/MyS3.java @@ -0,0 +1,38 @@ +package io.quarkus.it.amazon.lambda; + +import org.junit.jupiter.api.Assertions; + +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import com.amazonaws.services.lambda.runtime.events.S3Event; +import com.amazonaws.services.lambda.runtime.events.models.s3.S3EventNotification; + +public class MyS3 implements RequestHandler { + + @Override + public String handleRequest(S3Event event, Context context) { + Assertions.assertEquals(1, event.getRecords().size()); + S3EventNotification.S3EventNotificationRecord record = event.getRecords().get(0); + Assertions.assertEquals("2.0", record.getEventVersion()); + Assertions.assertEquals("aws:s3", record.getEventSource()); + Assertions.assertEquals("us-west-2", record.getAwsRegion()); + Assertions.assertEquals("1970-01-01T00:00:00.000Z", record.getEventTime().toString()); + Assertions.assertEquals("ObjectCreated:Put", record.getEventName()); + Assertions.assertEquals("AIDAJDPLRKLG7UEXAMPLE", record.getUserIdentity().getPrincipalId()); + Assertions.assertEquals("127.0.0.1", record.getRequestParameters().getSourceIPAddress()); + Assertions.assertEquals("C3D13FE58DE4C810", record.getResponseElements().getxAmzRequestId()); + Assertions.assertEquals("FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD", + record.getResponseElements().getxAmzId2()); + + Assertions.assertEquals("1.0", record.getS3().getS3SchemaVersion()); + Assertions.assertEquals("testConfigRule", record.getS3().getConfigurationId()); + Assertions.assertEquals("sourcebucket", record.getS3().getBucket().getName()); + Assertions.assertEquals("arn:aws:s3:::sourcebucket", record.getS3().getBucket().getArn()); + Assertions.assertEquals("A3NL1KOZZKExample", record.getS3().getBucket().getOwnerIdentity().getPrincipalId()); + Assertions.assertEquals("HappyFace.jpg", record.getS3().getObject().getKey()); + Assertions.assertEquals(1024, record.getS3().getObject().getSizeAsLong()); + Assertions.assertEquals("d41d8cd98f00b204e9800998ecf8427e", record.getS3().getObject().geteTag()); + Assertions.assertEquals("096fKKXTRTtl3on89fVO.nfljtsv6qko", record.getS3().getObject().getVersionId()); + return "Ok"; + } +} diff --git a/integration-tests/amazon-lambda-s3event/src/main/resources/application.properties b/integration-tests/amazon-lambda-s3event/src/main/resources/application.properties new file mode 100644 index 0000000000000..e04a99c3c9f73 --- /dev/null +++ b/integration-tests/amazon-lambda-s3event/src/main/resources/application.properties @@ -0,0 +1 @@ +quarkus.lambda.enable-polling-jvm-mode=true \ No newline at end of file diff --git a/integration-tests/amazon-lambda-s3event/src/test/java/io/quarkus/it/amazon/lambda/S3EventIT.java b/integration-tests/amazon-lambda-s3event/src/test/java/io/quarkus/it/amazon/lambda/S3EventIT.java new file mode 100644 index 0000000000000..e322fd8ef5aa7 --- /dev/null +++ b/integration-tests/amazon-lambda-s3event/src/test/java/io/quarkus/it/amazon/lambda/S3EventIT.java @@ -0,0 +1,7 @@ +package io.quarkus.it.amazon.lambda; + +import io.quarkus.test.junit.NativeImageTest; + +@NativeImageTest +public class S3EventIT extends S3EventTestCase { +} diff --git a/integration-tests/amazon-lambda-s3event/src/test/java/io/quarkus/it/amazon/lambda/S3EventTestCase.java b/integration-tests/amazon-lambda-s3event/src/test/java/io/quarkus/it/amazon/lambda/S3EventTestCase.java new file mode 100644 index 0000000000000..9a3581e9f8415 --- /dev/null +++ b/integration-tests/amazon-lambda-s3event/src/test/java/io/quarkus/it/amazon/lambda/S3EventTestCase.java @@ -0,0 +1,57 @@ +package io.quarkus.it.amazon.lambda; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.quarkus.amazon.lambda.test.LambdaClient; +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class S3EventTestCase { + + static String json = "{\n" + + " \"Records\":[\n" + + " {\n" + + " \"eventVersion\":\"2.0\",\n" + + " \"eventSource\":\"aws:s3\",\n" + + " \"awsRegion\":\"us-west-2\",\n" + + " \"eventTime\":\"1970-01-01T00:00:00.000Z\",\n" + + " \"eventName\":\"ObjectCreated:Put\",\n" + + " \"userIdentity\":{\n" + + " \"principalId\":\"AIDAJDPLRKLG7UEXAMPLE\"\n" + + " },\n" + + " \"requestParameters\":{\n" + + " \"sourceIPAddress\":\"127.0.0.1\"\n" + + " },\n" + + " \"responseElements\":{\n" + + " \"x-amz-request-id\":\"C3D13FE58DE4C810\",\n" + + " \"x-amz-id-2\":\"FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD\"\n" + + " },\n" + + " \"s3\":{\n" + + " \"s3SchemaVersion\":\"1.0\",\n" + + " \"configurationId\":\"testConfigRule\",\n" + + " \"bucket\":{\n" + + " \"name\":\"sourcebucket\",\n" + + " \"ownerIdentity\":{\n" + + " \"principalId\":\"A3NL1KOZZKExample\"\n" + + " },\n" + + " \"arn\":\"arn:aws:s3:::sourcebucket\"\n" + + " },\n" + + " \"object\":{\n" + + " \"key\":\"HappyFace.jpg\",\n" + + " \"size\":1024,\n" + + " \"eTag\":\"d41d8cd98f00b204e9800998ecf8427e\",\n" + + " \"versionId\":\"096fKKXTRTtl3on89fVO.nfljtsv6qko\"\n" + + " }\n" + + " }\n" + + " }\n" + + " ]\n" + + "}"; + + @Test + public void testS3() throws Exception { + String out = LambdaClient.invokeJson(String.class, json); + Assertions.assertEquals("Ok", out); + } + +} diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index b0442c739024b..a863043924b9f 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -85,6 +85,7 @@ amazon-services test-extension amazon-lambda + amazon-lambda-s3event amazon-lambda-stream-handler amazon-lambda-http amazon-lambda-http-resteasy diff --git a/test-framework/amazon-lambda/src/main/java/io/quarkus/amazon/lambda/test/LambdaClient.java b/test-framework/amazon-lambda/src/main/java/io/quarkus/amazon/lambda/test/LambdaClient.java index 37439a471680c..faab9e939e313 100644 --- a/test-framework/amazon-lambda/src/main/java/io/quarkus/amazon/lambda/test/LambdaClient.java +++ b/test-framework/amazon-lambda/src/main/java/io/quarkus/amazon/lambda/test/LambdaClient.java @@ -91,6 +91,14 @@ public String setValue(String value) { } } + /** + * Marshalls input and output as JSON using Jackson + * + * @param returnType + * @param input + * @param + * @return + */ public static T invoke(Class returnType, Object input) { if (problem != null) { throw new RuntimeException(problem); @@ -132,6 +140,54 @@ public String setValue(String value) { } } + /** + * Takes a json string as input. Unmarshalls return value using Jackson. + * + * @param returnType + * @param json + * @param + * @return + */ + public static T invokeJson(Class returnType, String json) { + if (problem != null) { + throw new RuntimeException(problem); + } + try { + final ObjectMapper mapper = getObjectMapper(); + String id = "aws-request-" + REQUEST_ID_GENERATOR.incrementAndGet(); + CompletableFuture result = new CompletableFuture<>(); + REQUESTS.put(id, result); + REQUEST_QUEUE.add(new Map.Entry() { + + @Override + public String getKey() { + return id; + } + + @Override + public String getValue() { + return json; + } + + @Override + public String setValue(String value) { + return null; + } + }); + String output = result.get(); + return mapper.readerFor(returnType).readValue(output); + } catch (Exception e) { + if (e instanceof ExecutionException) { + Throwable ex = e.getCause(); + if (ex instanceof RuntimeException) { + throw (RuntimeException) ex; + } + throw new RuntimeException(ex); + } + throw new RuntimeException(e); + } + } + private static ObjectMapper getObjectMapper() { ArcContainer container = Arc.container(); if (container == null) {