/*
* Copyright 2015-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazonaws.http;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.AmazonServiceException.ErrorType;
import com.amazonaws.DefaultRequest;
import com.amazonaws.internal.http.JsonErrorCodeParser;
import com.amazonaws.internal.http.JsonErrorMessageParser;
import com.amazonaws.protocol.json.JsonContent;
import com.amazonaws.transform.JsonErrorUnmarshaller;
import com.amazonaws.util.StringInputStream;
import com.amazonaws.util.StringUtils;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.JsonNode;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import static org.hamcrest.Matchers.hasEntry;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;
public class JsonErrorResponseHandlerTest {
private static final String SERVICE_NAME = "someService";
private static final String ERROR_CODE = "someErrorCode";
private JsonErrorResponseHandler responseHandler;
private HttpResponse httpResponse;
@Mock
private JsonErrorUnmarshaller unmarshaller;
@Mock
private JsonErrorCodeParser errorCodeParser;
@Before
public void setup() throws UnsupportedEncodingException {
MockitoAnnotations.initMocks(this);
when(errorCodeParser
.parseErrorCode((HttpResponse) anyObject(), (JsonContent) anyObject()))
.thenReturn(ERROR_CODE);
httpResponse = new HttpResponse(new DefaultRequest<String>(SERVICE_NAME), null);
httpResponse.setContent(new StringInputStream("{}"));
responseHandler = new JsonErrorResponseHandler(Arrays.asList(unmarshaller), errorCodeParser,
JsonErrorMessageParser.DEFAULT_ERROR_MESSAGE_PARSER,
new JsonFactory());
}
@Test
public void handle_NoUnmarshallersAdded_ReturnsGenericAmazonServiceException() throws
Exception {
responseHandler = new JsonErrorResponseHandler(new ArrayList<JsonErrorUnmarshaller>(),
new JsonErrorCodeParser(),
JsonErrorMessageParser.DEFAULT_ERROR_MESSAGE_PARSER,
new JsonFactory());
AmazonServiceException ase = responseHandler.handle(httpResponse);
assertNotNull(ase);
}
@Test
public void handle_NoMatchingUnmarshallers_ReturnsGenericAmazonServiceException() throws
Exception {
expectUnmarshallerDoesNotMatch();
AmazonServiceException ase = responseHandler.handle(httpResponse);
assertNotNull(ase);
}
@Test
public void handle_NullContent_ReturnsGenericAmazonServiceException() throws Exception {
httpResponse.setStatusCode(500);
httpResponse.setContent(null);
AmazonServiceException ase = responseHandler.handle(httpResponse);
// We assert these common properties are set again to make sure that code path is exercised
// for unknown AmazonServiceExceptions as well
assertEquals(ERROR_CODE, ase.getErrorCode());
assertEquals(500, ase.getStatusCode());
assertEquals(SERVICE_NAME, ase.getServiceName());
assertEquals(ErrorType.Service, ase.getErrorType());
}
@Test
public void handle_EmptyContent_ReturnsGenericAmazonServiceException() throws Exception {
httpResponse.setStatusCode(500);
httpResponse.setContent(new StringInputStream(""));
AmazonServiceException ase = responseHandler.handle(httpResponse);
assertNotNull(ase);
}
@Test
public void handle_UnmarshallerReturnsNull_ReturnsGenericAmazonServiceException() throws
Exception {
expectUnmarshallerMatches();
AmazonServiceException ase = responseHandler.handle(httpResponse);
assertNotNull(ase);
assertEquals(ERROR_CODE, ase.getErrorCode());
}
@Test
public void handle_UnmarshallerThrowsException_ReturnsGenericAmazonServiceException() throws
Exception {
expectUnmarshallerMatches();
when(unmarshaller.unmarshall((JsonNode) anyObject())).thenThrow(new RuntimeException());
AmazonServiceException ase = responseHandler.handle(httpResponse);
assertNotNull(ase);
assertEquals(ERROR_CODE, ase.getErrorCode());
}
@Test
public void handle_UnmarshallerReturnsException_ClientErrorType() throws Exception {
httpResponse.setStatusCode(400);
expectUnmarshallerMatches();
when(unmarshaller.unmarshall((JsonNode) anyObject()))
.thenReturn(new CustomException("error"));
AmazonServiceException ase = responseHandler.handle(httpResponse);
assertEquals(ERROR_CODE, ase.getErrorCode());
assertEquals(400, ase.getStatusCode());
assertEquals(SERVICE_NAME, ase.getServiceName());
assertEquals(ErrorType.Client, ase.getErrorType());
}
@Test
public void handle_UnmarshallerReturnsException_ServiceErrorType() throws Exception {
httpResponse.setStatusCode(500);
expectUnmarshallerMatches();
when(unmarshaller.unmarshall((JsonNode) anyObject()))
.thenReturn(new CustomException("error"));
AmazonServiceException ase = responseHandler.handle(httpResponse);
assertEquals(ErrorType.Service, ase.getErrorType());
}
@Test
public void handle_UnmarshallerReturnsException_WithRequestId() throws Exception {
httpResponse.setStatusCode(500);
httpResponse.addHeader(HttpResponseHandler.X_AMZN_REQUEST_ID_HEADER, "1234");
expectUnmarshallerMatches();
when(unmarshaller.unmarshall((JsonNode) anyObject()))
.thenReturn(new CustomException("error"));
AmazonServiceException ase = responseHandler.handle(httpResponse);
assertEquals("1234", ase.getRequestId());
}
/**
* Headers are case insensitive so the request id should still be parsed in this test
*/
@Test
public void handle_UnmarshallerReturnsException_WithCaseInsensitiveRequestId() throws
Exception {
httpResponse.setStatusCode(500);
httpResponse.addHeader(StringUtils.upperCase(HttpResponseHandler.X_AMZN_REQUEST_ID_HEADER),
"1234");
expectUnmarshallerMatches();
when(unmarshaller.unmarshall((JsonNode) anyObject()))
.thenReturn(new CustomException("error"));
AmazonServiceException ase = responseHandler.handle(httpResponse);
assertEquals("1234", ase.getRequestId());
}
/**
* All headers (Including ones that populate other fields like request id) should be dumped into
* the header map.
*/
@Test
public void handle_AllHeaders_DumpedIntoHeaderMap() throws Exception {
httpResponse.setStatusCode(500);
httpResponse.addHeader("FooHeader", "FooValue");
httpResponse.addHeader(HttpResponseHandler.X_AMZN_REQUEST_ID_HEADER, "1234");
expectUnmarshallerMatches();
when(unmarshaller.unmarshall((JsonNode) anyObject()))
.thenReturn(new CustomException("error"));
AmazonServiceException ase = responseHandler.handle(httpResponse);
assertThat(ase.getHttpHeaders(), hasEntry("FooHeader", "FooValue"));
assertThat(ase.getHttpHeaders(),
hasEntry(HttpResponseHandler.X_AMZN_REQUEST_ID_HEADER, "1234"));
}
private void expectUnmarshallerMatches() throws Exception {
when(unmarshaller.matchErrorCode(anyString())).thenReturn(true);
}
private void expectUnmarshallerDoesNotMatch() throws Exception {
when(unmarshaller.matchErrorCode(anyString())).thenReturn(false);
}
private static class CustomException extends AmazonServiceException {
private static final long serialVersionUID = 1305027296023640779L;
public CustomException(String errorMessage) {
super(errorMessage);
}
}
}