Skip to content

Commit fcf238f

Browse files
committed
Merge branch 'mikaelq-fix-exception-return-200' into core for PR #272
2 parents b6d6189 + 0896370 commit fcf238f

File tree

9 files changed

+108
-28
lines changed

9 files changed

+108
-28
lines changed

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandler.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.slf4j.Logger;
2323
import org.slf4j.LoggerFactory;
2424

25+
import javax.ws.rs.InternalServerErrorException;
2526
import javax.ws.rs.core.HttpHeaders;
2627
import javax.ws.rs.core.MediaType;
2728

@@ -31,7 +32,8 @@
3132
/**
3233
* Default implementation of the <code>ExceptionHandler</code> object that returns AwsProxyResponse objects.
3334
*
34-
* Returns application/json messages with a status code of 500 when the RequestReader failed to read the incoming event.
35+
* Returns application/json messages with a status code of 500 when the RequestReader failed to read the incoming event
36+
* or if InternalServerErrorException is thrown.
3537
* For all other exceptions returns a 502. Responses are populated with a JSON object containing a message property.
3638
*
3739
* @see ExceptionHandler
@@ -76,7 +78,7 @@ public AwsProxyResponse handle(Throwable ex) {
7678
// adding a print stack trace in case we have no appender or we are running inside SAM local, where need the
7779
// output to go to the stderr.
7880
ex.printStackTrace();
79-
if (ex instanceof InvalidRequestEventException) {
81+
if (ex instanceof InvalidRequestEventException || ex instanceof InternalServerErrorException) {
8082
return new AwsProxyResponse(500, headers, getErrorJson(INTERNAL_SERVER_ERROR));
8183
} else {
8284
return new AwsProxyResponse(502, headers, getErrorJson(GATEWAY_TIMEOUT_ERROR));

aws-serverless-java-container-core/src/test/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandlerTest.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
import com.amazonaws.serverless.exceptions.InvalidRequestEventException;
55
import com.amazonaws.serverless.exceptions.InvalidResponseObjectException;
6-
import com.amazonaws.serverless.proxy.AwsProxyExceptionHandler;
76
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
87
import com.amazonaws.serverless.proxy.model.ErrorModel;
98
import com.fasterxml.jackson.core.JsonProcessingException;
@@ -16,18 +15,22 @@
1615

1716
import org.junit.Before;
1817
import org.junit.Test;
18+
import org.mockito.Mockito;
1919

20+
import javax.ws.rs.InternalServerErrorException;
2021
import javax.ws.rs.core.HttpHeaders;
2122
import javax.ws.rs.core.MediaType;
2223
import java.io.*;
2324

2425

2526
public class AwsProxyExceptionHandlerTest {
27+
private static final String INTERNAL_SERVER_ERROR_MESSAGE = "Internal server error";
2628
private static final String INVALID_REQUEST_MESSAGE = "Invalid request error";
2729
private static final String INVALID_RESPONSE_MESSAGE = "Invalid response error";
2830
private AwsProxyExceptionHandler exceptionHandler;
2931
private ObjectMapper objectMapper;
3032

33+
3134
@Before
3235
public void setUp() {
3336
exceptionHandler = new AwsProxyExceptionHandler();
@@ -88,6 +91,44 @@ public void typedHandle_InvalidResponseObjectException_jsonContentTypeHeader() {
8891
assertEquals(MediaType.APPLICATION_JSON, resp.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE));
8992
}
9093

94+
@Test
95+
public void typedHandle_InternalServerErrorException_500State() {
96+
// Needed to mock InternalServerErrorException because it leverages RuntimeDelegate to set an internal
97+
// response object.
98+
InternalServerErrorException mockInternalServerErrorException = Mockito.mock(InternalServerErrorException.class);
99+
Mockito.when(mockInternalServerErrorException.getMessage()).thenReturn(INTERNAL_SERVER_ERROR_MESSAGE);
100+
101+
AwsProxyResponse resp = exceptionHandler.handle(mockInternalServerErrorException);
102+
103+
assertNotNull(resp);
104+
assertEquals(500, resp.getStatusCode());
105+
}
106+
107+
@Test
108+
public void typedHandle_InternalServerErrorException_responseString()
109+
throws JsonProcessingException {
110+
InternalServerErrorException mockInternalServerErrorException = Mockito.mock(InternalServerErrorException.class);
111+
Mockito.when(mockInternalServerErrorException.getMessage()).thenReturn(INTERNAL_SERVER_ERROR_MESSAGE);
112+
113+
AwsProxyResponse resp = exceptionHandler.handle(mockInternalServerErrorException);
114+
115+
assertNotNull(resp);
116+
String body = objectMapper.writeValueAsString(new ErrorModel(AwsProxyExceptionHandler.INTERNAL_SERVER_ERROR));
117+
assertEquals(body, resp.getBody());
118+
}
119+
120+
@Test
121+
public void typedHandle_InternalServerErrorException_jsonContentTypeHeader() {
122+
InternalServerErrorException mockInternalServerErrorException = Mockito.mock(InternalServerErrorException.class);
123+
Mockito.when(mockInternalServerErrorException.getMessage()).thenReturn(INTERNAL_SERVER_ERROR_MESSAGE);
124+
125+
AwsProxyResponse resp = exceptionHandler.handle(mockInternalServerErrorException);
126+
127+
assertNotNull(resp);
128+
assertTrue(resp.getMultiValueHeaders().containsKey(HttpHeaders.CONTENT_TYPE));
129+
assertEquals(MediaType.APPLICATION_JSON, resp.getMultiValueHeaders().getFirst(HttpHeaders.CONTENT_TYPE));
130+
}
131+
91132
@Test
92133
public void typedHandle_NullPointerException_responseObject()
93134
throws JsonProcessingException {

aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyServletResponseWriter.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,8 @@ public void commit() {
122122

123123

124124
public void failure(Throwable throwable) {
125-
try {
126-
log.error("failure", throwable);
127-
jerseyLatch.countDown();
128-
servletResponse.flushBuffer();
129-
} catch (IOException e) {
130-
log.error("Could not fail response", e);
131-
throw new InternalServerErrorException(e);
132-
}
125+
log.error("failure", throwable);
126+
throw new InternalServerErrorException("Jersey failed to process request", throwable);
133127
}
134128

135129

aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/EchoJerseyResource.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
2525
import org.glassfish.jersey.media.multipart.FormDataParam;
2626

27+
import javax.inject.Inject;
2728
import javax.servlet.ServletContext;
2829
import javax.servlet.http.HttpServletRequest;
2930
import javax.servlet.http.HttpServletResponse;
@@ -59,6 +60,9 @@ public class EchoJerseyResource {
5960
@Context
6061
SecurityContext securityCtx;
6162

63+
@Inject
64+
JerseyDependency jerseyDependency;
65+
6266
@Path("/decoded-param") @GET
6367
@Produces(MediaType.APPLICATION_JSON)
6468
public SingleValueModel echoDecodedParam(@QueryParam("param") String param) {

aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyTest.java

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,15 @@
1414

1515

1616
import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
17-
import com.amazonaws.serverless.proxy.jersey.providers.ServletRequestFilter;
18-
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
19-
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
2017
import com.amazonaws.serverless.proxy.internal.servlet.AwsServletContext;
21-
import com.amazonaws.serverless.proxy.jersey.model.MapResponseModel;
22-
import com.amazonaws.serverless.proxy.jersey.model.SingleValueModel;
2318
import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
2419
import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
20+
import com.amazonaws.serverless.proxy.jersey.model.MapResponseModel;
21+
import com.amazonaws.serverless.proxy.jersey.model.SingleValueModel;
22+
import com.amazonaws.serverless.proxy.jersey.providers.ServletRequestFilter;
23+
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
24+
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
2525
import com.amazonaws.services.lambda.runtime.Context;
26-
2726
import com.fasterxml.jackson.core.JsonProcessingException;
2827
import com.fasterxml.jackson.databind.ObjectMapper;
2928
import org.apache.commons.codec.binary.Base64;
@@ -37,13 +36,15 @@
3736
import javax.ws.rs.core.HttpHeaders;
3837
import javax.ws.rs.core.MediaType;
3938
import javax.ws.rs.core.Response;
40-
4139
import java.io.IOException;
4240
import java.util.Arrays;
4341
import java.util.Collection;
4442
import java.util.UUID;
4543

46-
import static org.junit.Assert.*;
44+
import static org.junit.Assert.assertEquals;
45+
import static org.junit.Assert.assertNotNull;
46+
import static org.junit.Assert.assertTrue;
47+
import static org.junit.Assert.fail;
4748

4849
/**
4950
* Unit test class for the Jersey AWS_PROXY default implementation
@@ -57,13 +58,26 @@ public class JerseyAwsProxyTest {
5758

5859

5960
private static ObjectMapper objectMapper = new ObjectMapper();
61+
6062
private static ResourceConfig app = new ResourceConfig().packages("com.amazonaws.serverless.proxy.jersey")
63+
.register(LoggingFeature.class)
64+
.register(ServletRequestFilter.class)
65+
.register(MultiPartFeature.class)
66+
.register(new ResourceBinder())
67+
.property(LoggingFeature.LOGGING_FEATURE_VERBOSITY_SERVER, LoggingFeature.Verbosity.PAYLOAD_ANY);
68+
69+
private static ResourceConfig appWithoutRegisteredDependencies = new ResourceConfig()
70+
.packages("com.amazonaws.serverless.proxy.jersey")
6171
.register(LoggingFeature.class)
6272
.register(ServletRequestFilter.class)
6373
.register(MultiPartFeature.class)
6474
.property(LoggingFeature.LOGGING_FEATURE_VERBOSITY_SERVER, LoggingFeature.Verbosity.PAYLOAD_ANY);
75+
6576
private static JerseyLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler = JerseyLambdaContainerHandler.getAwsProxyHandler(app);
6677

78+
private static JerseyLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handlerWithoutRegisteredDependencies
79+
= JerseyLambdaContainerHandler.getAwsProxyHandler(appWithoutRegisteredDependencies);
80+
6781
private static Context lambdaContext = new MockLambdaContext();
6882

6983
private boolean isAlb;
@@ -76,15 +90,14 @@ public JerseyAwsProxyTest(boolean alb) {
7690
public static Collection<Object> data() {
7791
return Arrays.asList(new Object[] { false, true });
7892
}
79-
93+
8094
private AwsProxyRequestBuilder getRequestBuilder(String path, String method) {
8195
AwsProxyRequestBuilder builder = new AwsProxyRequestBuilder(path, method);
8296
if (isAlb) builder.alb();
83-
97+
8498
return builder;
8599
}
86100

87-
88101
@Test
89102
public void alb_basicRequest_expectSuccess() {
90103
AwsProxyRequest request = getRequestBuilder("/echo/headers", "GET")
@@ -130,6 +143,18 @@ public void headers_servletRequest_echo() {
130143
validateMapResponseModel(output);
131144
}
132145

146+
@Test
147+
public void headers_servletRequest_failedDependencyInjection_expectInternalServerError() {
148+
AwsProxyRequest request = getRequestBuilder("/echo/servlet-headers", "GET")
149+
.json()
150+
.header(CUSTOM_HEADER_KEY, CUSTOM_HEADER_VALUE)
151+
.build();
152+
153+
AwsProxyResponse output = handlerWithoutRegisteredDependencies.proxy(request, lambdaContext);
154+
assertEquals("application/json", output.getMultiValueHeaders().getFirst("Content-Type"));
155+
assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), output.getStatusCode());
156+
}
157+
133158
@Test
134159
public void context_servletResponse_setCustomHeader() {
135160
AwsProxyRequest request = getRequestBuilder("/echo/servlet-response", "GET")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.amazonaws.serverless.proxy.jersey;
2+
3+
// This class is used to test HK2 dependency injection.
4+
public class JerseyDependency {
5+
6+
}

aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyInjectionTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
*/
3131
public class JerseyInjectionTest {
3232

33-
// Test ressource binder
33+
// Test resource binder
3434
private static class ResourceBinder extends AbstractBinder {
3535

3636
@Override

aws-serverless-java-container-jersey/src/test/java/com/amazonaws/serverless/proxy/jersey/JerseyParamEncodingTest.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import com.amazonaws.services.lambda.runtime.Context;
1212

1313
import com.fasterxml.jackson.databind.ObjectMapper;
14-
import org.glassfish.jersey.logging.LoggingFeature;
1514
import org.glassfish.jersey.media.multipart.MultiPartFeature;
1615
import org.glassfish.jersey.server.ResourceConfig;
1716
import org.junit.Ignore;
@@ -26,10 +25,6 @@
2625
import java.net.URLEncoder;
2726
import java.util.Arrays;
2827
import java.util.Collection;
29-
import java.util.logging.ConsoleHandler;
30-
import java.util.logging.Level;
31-
import java.util.logging.Logger;
32-
import java.util.logging.SimpleFormatter;
3328

3429
import static org.junit.Assert.assertEquals;
3530
import static org.junit.Assert.assertNotNull;
@@ -69,6 +64,7 @@ public class JerseyParamEncodingTest {
6964
private static ObjectMapper objectMapper = new ObjectMapper();
7065
private static ResourceConfig app = new ResourceConfig().packages("com.amazonaws.serverless.proxy.jersey")
7166
.register(MultiPartFeature.class)
67+
.register(new ResourceBinder())
7268
.property("jersey.config.server.tracing.type", "ALL")
7369
.property("jersey.config.server.tracing.threshold", "VERBOSE");
7470
private static JerseyLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler = JerseyLambdaContainerHandler.getAwsProxyHandler(app);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.amazonaws.serverless.proxy.jersey;
2+
3+
import org.glassfish.jersey.internal.inject.AbstractBinder;
4+
5+
import javax.inject.Singleton;
6+
7+
public class ResourceBinder extends AbstractBinder {
8+
@Override
9+
protected void configure() {
10+
bind(new JerseyDependency()).to(JerseyDependency.class).in(Singleton.class);
11+
}
12+
}

0 commit comments

Comments
 (0)