Skip to content

Commit

Permalink
Merge pull request #40464 from hamburml/feature/AmazonLambdaHandlerCo…
Browse files Browse the repository at this point in the history
…llections

Fix correct parsing of collections in AmazonLambdaRecorder
  • Loading branch information
gsmet authored Jul 4, 2024
2 parents deff9c6 + df27b36 commit 0c20277
Show file tree
Hide file tree
Showing 14 changed files with 263 additions and 51 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.quarkus.amazon.lambda.deployment.testing;

import java.util.ArrayList;
import java.util.List;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import io.quarkus.amazon.lambda.deployment.testing.model.InputPerson;
import io.quarkus.amazon.lambda.deployment.testing.model.OutputPerson;

public abstract class AbstractInputCollectionOutputCollection implements RequestHandler<List<InputPerson>, List<OutputPerson>> {

@Override
public List<OutputPerson> handleRequest(List<InputPerson> inputPeronList, Context context) {
List<OutputPerson> personList = new ArrayList<>();
inputPeronList.forEach(person -> personList.add(new OutputPerson(person.getName())));
return personList;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.quarkus.amazon.lambda.deployment.testing;

public class AbstractInputCollectionOutputCollectionLambdaImpl extends AbstractInputCollectionOutputCollection {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.quarkus.amazon.lambda.deployment.testing;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.hasEntry;

import java.util.ArrayList;
import java.util.List;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.amazon.lambda.deployment.testing.model.InputPerson;
import io.quarkus.amazon.lambda.deployment.testing.model.OutputPerson;
import io.quarkus.test.QuarkusUnitTest;

public class AbstractInputCollectionOutputCollectionLambdaImplTest {

@RegisterExtension
static final QuarkusUnitTest test = new QuarkusUnitTest().setArchiveProducer(() -> ShrinkWrap
.create(JavaArchive.class)
.addClasses(AbstractInputCollectionOutputCollectionLambdaImpl.class, AbstractInputCollectionOutputCollection.class,
InputPerson.class, OutputPerson.class));

@Test
void abstractRequestHandler_InputCollectionInputPerson_OutputCollectionOutputPerson() {

List<InputPerson> personList = new ArrayList<>();
personList.add(new InputPerson("Chris"));
personList.add(new InputPerson("Fred"));

given()
.body(personList)
.when()
.post()
.then()
.statusCode(200)
.body("", hasItem(hasEntry("outputname", "Chris"))) // OutputPerson serializes name with key outputname
.body("", hasItem(hasEntry("outputname", "Fred")))
.body("", not(hasItem(hasEntry("name", "Chris")))) // make sure that there is no key name
.body("", not(hasItem(hasEntry("name", "Fred"))));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

public class GreetingLambda implements RequestHandler<Person, String> {
import io.quarkus.amazon.lambda.deployment.testing.model.InputPerson;

public class GreetingLambda implements RequestHandler<InputPerson, String> {

@Override
public String handleRequest(Person input, Context context) {
public String handleRequest(InputPerson input, Context context) {
return "Hey " + input.getName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.quarkus.amazon.lambda.deployment.testing;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.containsString;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.amazon.lambda.deployment.testing.model.InputPerson;
import io.quarkus.test.QuarkusUnitTest;

class GreetingLambdaTest {

@RegisterExtension
static final QuarkusUnitTest test = new QuarkusUnitTest().setArchiveProducer(() -> ShrinkWrap
.create(JavaArchive.class)
.addClasses(GreetingLambda.class, InputPerson.class));

@Test
public void requestHandler_InputPerson_OutputString() throws Exception {
// you test your lambdas by invoking on http://localhost:8081
// this works in dev mode too

InputPerson in = new InputPerson("Stu");
given()
.contentType("application/json")
.accept("application/json")
.body(in)
.when()
.post()
.then()
.statusCode(200)
.body(containsString("Hey Stu"));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.quarkus.amazon.lambda.deployment.testing;

import java.util.ArrayList;
import java.util.List;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import io.quarkus.amazon.lambda.deployment.testing.model.InputPerson;
import io.quarkus.amazon.lambda.deployment.testing.model.OutputPerson;

public class InputCollectionOutputCollectionLambda implements RequestHandler<List<InputPerson>, List<OutputPerson>> {

@Override
public List<OutputPerson> handleRequest(List<InputPerson> people, Context context) {

List<OutputPerson> outputPeople = new ArrayList<>();
people.stream().parallel().forEach((person) -> {
outputPeople.add(new OutputPerson(person.getName()));
});

return outputPeople;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.quarkus.amazon.lambda.deployment.testing;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.hasEntry;

import java.util.ArrayList;
import java.util.List;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.amazon.lambda.deployment.testing.model.InputPerson;
import io.quarkus.amazon.lambda.deployment.testing.model.OutputPerson;
import io.quarkus.test.QuarkusUnitTest;

public class InputCollectionOutputCollectionLambdaTest {

@RegisterExtension
static final QuarkusUnitTest test = new QuarkusUnitTest().setArchiveProducer(() -> ShrinkWrap
.create(JavaArchive.class)
.addClasses(InputCollectionOutputCollectionLambda.class, InputPerson.class, OutputPerson.class));

@Test
void requestHandler_InputCollectionInputPerson_OutputCollectionOutputPerson() {

List<InputPerson> personList = new ArrayList<>();
personList.add(new InputPerson("Chris"));
personList.add(new InputPerson("Fred"));

given()
.body(personList)
.when()
.post()
.then()
.statusCode(200)
.body("", hasItem(hasEntry("outputname", "Chris"))) // OutputPerson serializes name with key outputname
.body("", hasItem(hasEntry("outputname", "Fred")))
.body("", not(hasItem(hasEntry("name", "Chris")))) // make sure that there is no key name
.body("", not(hasItem(hasEntry("name", "Fred"))));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.amazon.lambda.deployment.testing.model.InputPerson;
import io.quarkus.amazon.lambda.deployment.testing.model.OutputPerson;
import io.quarkus.test.ContinuousTestingTestUtils;
import io.quarkus.test.QuarkusDevModeTest;

Expand All @@ -21,7 +23,7 @@ public class LambdaDevServicesContinuousTestingTestCase {
@Override
public JavaArchive get() {
return ShrinkWrap.create(JavaArchive.class)
.addClasses(GreetingLambda.class, Person.class)
.addClasses(GreetingLambda.class, InputPerson.class, OutputPerson.class)
.addAsResource(
new StringAsset(ContinuousTestingTestUtils.appProperties(
"quarkus.log.category.\"io.quarkus.amazon.lambda.runtime\".level=DEBUG")),
Expand All @@ -30,7 +32,7 @@ public JavaArchive get() {
}).setTestArchiveProducer(new Supplier<>() {
@Override
public JavaArchive get() {
return ShrinkWrap.create(JavaArchive.class).addClass(LambdaHandlerET.class);
return ShrinkWrap.create(JavaArchive.class).addClass(GreetingLambdaTest.class);
}
});

Expand All @@ -45,7 +47,7 @@ public void testLambda() throws Exception {
result = utils.waitForNextCompletion();
Assertions.assertEquals(0, result.getTotalTestsPassed());
Assertions.assertEquals(1, result.getTotalTestsFailed());
test.modifyTestSourceFile(LambdaHandlerET.class, s -> s.replace("Hey", "Yo"));
test.modifyTestSourceFile(GreetingLambdaTest.class, s -> s.replace("Hey", "Yo"));
result = utils.waitForNextCompletion();
Assertions.assertEquals(1, result.getTotalTestsPassed());
Assertions.assertEquals(0, result.getTotalTestsFailed());
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.quarkus.amazon.lambda.deployment.testing.model;

public class InputPerson {

public InputPerson() {
}

public InputPerson(String name) {
this.name = name;
}

private String name;

public String getName() {
return name;
}

public InputPerson setName(String name) {
this.name = name;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.quarkus.amazon.lambda.deployment.testing.model;

import com.fasterxml.jackson.annotation.JsonProperty;

public class OutputPerson {

public OutputPerson() {
}

public OutputPerson(String name) {
this.name = name;
}

@JsonProperty("outputname")
private String name;

public String getName() {
return name;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand All @@ -16,6 +17,7 @@
import com.amazonaws.services.lambda.runtime.events.S3Event;
import com.fasterxml.jackson.databind.ObjectMapper;

import io.quarkus.amazon.lambda.runtime.handlers.CollectionInputReader;
import io.quarkus.amazon.lambda.runtime.handlers.S3EventInputReader;
import io.quarkus.arc.runtime.BeanContainer;
import io.quarkus.runtime.LaunchMode;
Expand Down Expand Up @@ -53,11 +55,15 @@ static void initializeHandlerClass(Class<? extends RequestHandler<?, ?>> handler
ObjectMapper objectMapper = AmazonLambdaMapperRecorder.objectMapper;
Method handlerMethod = discoverHandlerMethod(handlerClass);
Class<?> parameterType = handlerMethod.getParameterTypes()[0];

if (parameterType.equals(S3Event.class)) {
objectReader = new S3EventInputReader(objectMapper);
} else if (Collection.class.isAssignableFrom(parameterType)) {
objectReader = new CollectionInputReader<>(objectMapper, handlerMethod);
} else {
objectReader = new JacksonInputReader(objectMapper.readerFor(parameterType));
}

objectWriter = new JacksonOutputWriter(objectMapper.writerFor(handlerMethod.getReturnType()));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.quarkus.amazon.lambda.runtime.handlers;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collection;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;

import io.quarkus.amazon.lambda.runtime.LambdaInputReader;

public class CollectionInputReader<T> implements LambdaInputReader<Collection<T>> {
final ObjectReader reader;

public CollectionInputReader(ObjectMapper mapper, Method handler) {
Type genericParameterType = handler.getGenericParameterTypes()[0];
JavaType constructParameterType = mapper.getTypeFactory().constructType(genericParameterType);
this.reader = mapper.readerFor(constructParameterType);
}

@Override
public Collection<T> readValue(InputStream is) throws IOException {
return this.reader.readValue(is);
}
}

0 comments on commit 0c20277

Please sign in to comment.