diff --git a/README.md b/README.md index d799936..dc73fae 100644 --- a/README.md +++ b/README.md @@ -11,15 +11,17 @@ i. Declare the dependency in your _pom.xml_ file. cloud.cirrusup aws-latency-request-log-handler - 1.0.0 + 1.1.0 ``` - ii. Create a _request handler_ object. - ```java AwsLatencyRequestLogHandler handler = new AwsLatencyRequestLogHandler(); ``` +If you want to publish call details in JSON format, then declare the handler in the following manner: +```java +AwsLatencyRequestLogHandler handler = new AwsLatencyRequestLogHandler(new JSONPublisher()); +``` iii. Enhance the _AWS client_ with the request handler created above. diff --git a/pom.xml b/pom.xml index fba470a..faa312c 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ cloud.cirrusup aws-latency-request-log-handler - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT jar @@ -124,13 +124,26 @@ - + com.amazonaws aws-java-sdk-core 1.11.397 + + com.amazonaws + aws-java-sdk-s3 + 1.11.397 + + + + + com.fasterxml.jackson.core + jackson-core + 2.9.7 + + org.slf4j diff --git a/src/main/java/cloud/cirrusup/AwsLatencyRequestLogHandler.java b/src/main/java/cloud/cirrusup/AwsLatencyRequestLogHandler.java index 20a495f..12ed4dc 100644 --- a/src/main/java/cloud/cirrusup/AwsLatencyRequestLogHandler.java +++ b/src/main/java/cloud/cirrusup/AwsLatencyRequestLogHandler.java @@ -1,12 +1,15 @@ package cloud.cirrusup; +import cloud.cirrusup.publisher.Publisher; +import cloud.cirrusup.publisher.PlainLogPublisher; +import cloud.cirrusup.publisher.model.PublishedInfo; import com.amazonaws.AmazonServiceException; import com.amazonaws.Request; import com.amazonaws.Response; import com.amazonaws.handlers.RequestHandler2; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.amazonaws.services.s3.model.AmazonS3Exception; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; /** @@ -14,17 +17,25 @@ */ public class AwsLatencyRequestLogHandler extends RequestHandler2 { - private static final String LOG_NAME = "aws-latency-log"; private static final String REQUEST_ID = "requestId"; - private static final Logger LOG = LoggerFactory.getLogger(LOG_NAME); - + private final Publisher publisher; private final ConcurrentHashMap REQUEST_MAP = new ConcurrentHashMap<>(); /** * Constructor. */ public AwsLatencyRequestLogHandler() { + + this(new PlainLogPublisher()); + } + + /** + * Constructor. + */ + public AwsLatencyRequestLogHandler(Publisher publisher) { + + this.publisher = publisher; } /** @@ -34,9 +45,6 @@ public AwsLatencyRequestLogHandler() { public void beforeRequest(Request request) { final String id = RandomGenerator.getUUIDRandomString(); - - LOG.info("ID [{}] - Request done to the service [{}] with the method [{}]", id, request.getServiceName(), request.getHttpMethod()); - request.getHeaders().put(REQUEST_ID, id); REQUEST_MAP.put(id, System.currentTimeMillis()); } @@ -48,14 +56,20 @@ public void beforeRequest(Request request) { public void afterResponse(Request request, Response response) { final String id = request.getHeaders().get(REQUEST_ID); - + PublishedInfo info = new PublishedInfo(); try { - LOG.info("Request ID [{}] took [{}] milliseconds and returned the RESPONSE_CODE [{}]", - id, getTime(id), getStatusCode(response, null)); + info.addInfo(PublishedInfo.SERVICE_NAME, request.getServiceName()); + info.addInfo(PublishedInfo.HTTP_METHOD, request.getHttpMethod().name()); + info.addInfo(PublishedInfo.API_METHOD, getApiMethod(request)); + info.addInfo(PublishedInfo.REQUEST_ID, getRequestId(request, response)); + info.addLatency(getTime(id)); + info.setStatusCode(getStatusCode(response, null)); } catch (Exception ex) { - LOG.error("ID [{}] for the request to [{}] was not found.", id, request.getServiceName()); + } finally { + + publisher.publish(info); } } @@ -66,15 +80,71 @@ public void afterResponse(Request request, Response response) { public void afterError(Request request, Response response, Exception e) { final String id = request.getHeaders().get(REQUEST_ID); - + PublishedInfo info = new PublishedInfo(); try { - LOG.error("Request ID [{}] took [{}] milliseconds and returned the RESPONSE_CODE [{}] and ERROR_MESSAGE [{}]", - id, getTime(id), getStatusCode(response, e), e.getMessage()); + info.addInfo(PublishedInfo.SERVICE_NAME, request.getServiceName()); + info.addInfo(PublishedInfo.HTTP_METHOD, request.getHttpMethod().name()); + info.addInfo(PublishedInfo.REQUEST_ID, getRequestId(e)); + info.addInfo(PublishedInfo.API_METHOD, getApiMethod(request)); + info.addInfo(PublishedInfo.ERROR_SUMMARY, e.getMessage()); + info.addLatency(getTime(id)); + info.setStatusCode(getStatusCode(response, e)); } catch (Exception ex) { - LOG.error("ID [{}] for the request to [{}] was not found.", id, request.getServiceName()); + } finally { + + publisher.publish(info); + } + } + + private String getApiMethod(Request request) { + + if (request != null && request.getHeaders() != null && request.getHeaders().containsKey("X-Amz-Target")) { + + return request.getHeaders().get("X-Amz-Target"); } + + if (request != null && request.getParameters() != null && request.getParameters().containsKey("Action")) { + + List action = request.getParameters().get("Action"); + if (!action.isEmpty()) { + + return action.get(0); + } + } + + return null; + } + + private String getRequestId(Exception e) { + + if (e != null && e instanceof AmazonServiceException) { + + AmazonServiceException awsException = (AmazonServiceException) e; + if (awsException.getServiceName().equals("Amazon S3") && (awsException instanceof AmazonS3Exception)) { + + return awsException.getRequestId() + " " + ((AmazonS3Exception) e).getExtendedRequestId(); + } + return awsException.getRequestId(); + } + + return null; + } + + + private String getRequestId(Request request, Response response) { + + if (response != null && response.getHttpResponse() != null && response.getHttpResponse().getHeaders() != null) { + + if (request.getServiceName().equals("Amazon S3")) { + + return response.getHttpResponse().getHeaders().get("x-amz-request-id") + " " + response.getHttpResponse().getHeaders().get("x-amz-id-2"); + } + return response.getHttpResponse().getHeaders().get("x-amzn-RequestId"); + } + + return null; } private int getStatusCode(Response response, Exception e) { diff --git a/src/main/java/cloud/cirrusup/publisher/JSONPublisher.java b/src/main/java/cloud/cirrusup/publisher/JSONPublisher.java new file mode 100644 index 0000000..ed3b8c9 --- /dev/null +++ b/src/main/java/cloud/cirrusup/publisher/JSONPublisher.java @@ -0,0 +1,50 @@ +package cloud.cirrusup.publisher; + +import cloud.cirrusup.publisher.Publisher; +import cloud.cirrusup.publisher.model.PublishedInfo; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static cloud.cirrusup.publisher.model.PublishedInfo.API_METHOD; +import static cloud.cirrusup.publisher.model.PublishedInfo.ERROR_SUMMARY; +import static cloud.cirrusup.publisher.model.PublishedInfo.HTTP_METHOD; +import static cloud.cirrusup.publisher.model.PublishedInfo.REQUEST_ID; +import static cloud.cirrusup.publisher.model.PublishedInfo.SERVICE_NAME; + +/** + * Publisher that exports entries in JSON format. + */ +public class JSONPublisher implements Publisher { + + private static final ObjectMapper mapper = new ObjectMapper(); + private static final Logger LOG = LoggerFactory.getLogger(LOG_NAME); + + /** + * {@inheritDoc} + */ + @Override + public void publish(PublishedInfo info) { + + ObjectNode node = mapper.createObjectNode(); + node.put("requestId", info.getInfo(REQUEST_ID)); + node.put("serviceName", info.getInfo(SERVICE_NAME)); + node.put("httpMethod", info.getInfo(HTTP_METHOD)); + node.put("latency", info.getLatency()); + node.put("statusCode", info.getStatusCode()); + if (info.hasInfo(ERROR_SUMMARY)) { + node.put("errorMessage", info.getInfo(ERROR_SUMMARY)); + } + if (info.hasInfo(API_METHOD)) { + node.put("apiMethod", info.getInfo(API_METHOD)); + } + + try { + + LOG.info(mapper.writeValueAsString(node)); + } catch (JsonProcessingException e) { + } + } +} diff --git a/src/main/java/cloud/cirrusup/publisher/PlainLogPublisher.java b/src/main/java/cloud/cirrusup/publisher/PlainLogPublisher.java new file mode 100644 index 0000000..5f92d4d --- /dev/null +++ b/src/main/java/cloud/cirrusup/publisher/PlainLogPublisher.java @@ -0,0 +1,38 @@ +package cloud.cirrusup.publisher; + +import cloud.cirrusup.publisher.Publisher; +import cloud.cirrusup.publisher.model.PublishedInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static cloud.cirrusup.publisher.model.PublishedInfo.API_METHOD; +import static cloud.cirrusup.publisher.model.PublishedInfo.ERROR_SUMMARY; +import static cloud.cirrusup.publisher.model.PublishedInfo.HTTP_METHOD; +import static cloud.cirrusup.publisher.model.PublishedInfo.REQUEST_ID; +import static cloud.cirrusup.publisher.model.PublishedInfo.SERVICE_NAME; + +/** + * Publisher that uses a text log file to add plain info. + */ +public class PlainLogPublisher implements Publisher { + + private static final Logger LOG = LoggerFactory.getLogger(LOG_NAME); + + /** + * {@inheritDoc} + */ + @Override + public void publish(PublishedInfo info) { + + LOG.info("Request ID [{}] to [{}/{}] took [{}] milliseconds and returned the RESPONSE_CODE [{}]", + info.getInfo(REQUEST_ID), info.getInfo(SERVICE_NAME), info.getInfo(HTTP_METHOD), info.getLatency(), info.getStatusCode()); + + if (info.hasInfo(ERROR_SUMMARY)) { + LOG.warn("Request ID [{}], RESPONSE_CODE [{}], MESSAGE [{}]", info.getInfo(REQUEST_ID), info.getStatusCode(), info.getInfo(ERROR_SUMMARY)); + } + + if(info.hasInfo(API_METHOD)){ + LOG.info("Request ID [{}], API method [{}]", info.getInfo(REQUEST_ID), info.getInfo(API_METHOD)); + } + } +} diff --git a/src/main/java/cloud/cirrusup/publisher/Publisher.java b/src/main/java/cloud/cirrusup/publisher/Publisher.java new file mode 100644 index 0000000..e4532a5 --- /dev/null +++ b/src/main/java/cloud/cirrusup/publisher/Publisher.java @@ -0,0 +1,18 @@ +package cloud.cirrusup.publisher; + +import cloud.cirrusup.publisher.model.PublishedInfo; + +/** + * Model for any publisher. + */ +public interface Publisher { + + String LOG_NAME = "aws-latency-log"; + + /** + * Publish info in the underlying destination. + * + * @param info information to be published + */ + void publish(PublishedInfo info); +} diff --git a/src/main/java/cloud/cirrusup/publisher/model/PublishedInfo.java b/src/main/java/cloud/cirrusup/publisher/model/PublishedInfo.java new file mode 100644 index 0000000..20af318 --- /dev/null +++ b/src/main/java/cloud/cirrusup/publisher/model/PublishedInfo.java @@ -0,0 +1,57 @@ +package cloud.cirrusup.publisher.model; + +import java.util.HashMap; +import java.util.Map; + +/** + * POJO class that holds all details about info published. + */ +public class PublishedInfo { + + public static final String REQUEST_ID = "requestId"; + public static final String SERVICE_NAME = "serviceName"; + public static final String HTTP_METHOD = "httpMethod"; + public static final String ERROR_SUMMARY = "errorInfo"; + public static final String API_METHOD = "apiMethod"; + + + private final Map info = new HashMap<>(); + private long latency = -1; + private int statusCode = -1; + + + public void addLatency(long latency) { + + this.latency = latency; + } + + public void addInfo(String name, String value) { + + this.info.put(name, value); + } + + public long getLatency() { + + return latency; + } + + public String getInfo(String name) { + + return info.get(name); + } + + public boolean hasInfo(String name) { + + return info.containsKey(name) && info.get(name) != null; + } + + public void setStatusCode(int statusCode) { + + this.statusCode = statusCode; + } + + public int getStatusCode() { + + return statusCode; + } +} diff --git a/src/test/java/cloud/cirrusup/AwsLatencyRequestLogHandlerTest.java b/src/test/java/cloud/cirrusup/AwsLatencyRequestLogHandlerTest.java index 2a6c565..8a7927a 100644 --- a/src/test/java/cloud/cirrusup/AwsLatencyRequestLogHandlerTest.java +++ b/src/test/java/cloud/cirrusup/AwsLatencyRequestLogHandlerTest.java @@ -6,6 +6,7 @@ import com.amazonaws.Response; import com.amazonaws.http.HttpMethodName; import com.amazonaws.http.HttpResponse; +import com.amazonaws.services.s3.model.AmazonS3Exception; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; @@ -16,7 +17,6 @@ import java.util.Map; import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -41,6 +41,56 @@ public class AwsLatencyRequestLogHandlerTest { @Test public void testWithGoodRequestId() throws InterruptedException { + //setup + Request request = mock(Request.class); + Response response = PowerMockito.mock(Response.class); + HttpResponse httpResponse = mock(HttpResponse.class); + Map mapMock = mock(Map.class); + mockStatic(RandomGenerator.class); + + when(request.getServiceName()).thenReturn("AmazonSQS"); + when(request.getHttpMethod()).thenReturn(HttpMethodName.POST); + when(RandomGenerator.getUUIDRandomString()).thenReturn(REQUEST_VALUE); + when(request.getHeaders()).thenReturn(mapMock); + when(response.getHttpResponse()).thenReturn(httpResponse); + when(httpResponse.getStatusCode()).thenReturn(200); + when(httpResponse.getHeaders()).thenReturn(mapMock); + when(mapMock.get("x-amzn-RequestId")).thenReturn(REQUEST_VALUE); + when(mapMock.get("requestId")).thenReturn(REQUEST_VALUE); + + //call + awsLatencyRequestHandler.beforeRequest(request); + Thread.sleep(150); + awsLatencyRequestHandler.afterResponse(request, response); + + //verify + verify(request, times(4)).getHeaders(); + verify(request, times(2)).getParameters(); + verify(response, times(5)).getHttpResponse(); + verify(request, times(1)).getHttpMethod(); + verify(request, times(2)).getServiceName(); + verify(httpResponse, times(1)).getStatusCode(); + verify(httpResponse, times(2)).getHeaders(); + verify(mapMock, times(1)).put(anyString(), anyString()); + verify(mapMock, times(1)).get("requestId"); + verify(mapMock, times(1)).get("x-amzn-RequestId"); + verify(mapMock, times(1)).containsKey("X-Amz-Target"); + verifyNoMoreInteractions(request); + verifyNoMoreInteractions(httpResponse); + verifyNoMoreInteractions(mapMock); + + PowerMockito.verifyStatic(times(1)); + RandomGenerator.getUUIDRandomString(); + PowerMockito.verifyNoMoreInteractions(RandomGenerator.class); + + assertEquals(SERVICE_NAME, request.getServiceName()); + assertEquals(HttpMethodName.POST, request.getHttpMethod()); + assertEquals(REQUEST_VALUE, request.getHeaders().get(REQUEST_ID)); + assertEquals(200, httpResponse.getStatusCode()); + } + + @Test + public void testWithMethodName() throws InterruptedException { //setup Request request = mock(Request.class); @@ -53,9 +103,13 @@ public void testWithGoodRequestId() throws InterruptedException { when(request.getHttpMethod()).thenReturn(HttpMethodName.POST); when(RandomGenerator.getUUIDRandomString()).thenReturn(REQUEST_VALUE); when(request.getHeaders()).thenReturn(mapMock); - when(mapMock.get(any())).thenReturn(REQUEST_VALUE); when(response.getHttpResponse()).thenReturn(httpResponse); when(httpResponse.getStatusCode()).thenReturn(200); + when(httpResponse.getHeaders()).thenReturn(mapMock); + when(mapMock.get("x-amzn-RequestId")).thenReturn(REQUEST_VALUE); + when(mapMock.get("requestId")).thenReturn(REQUEST_VALUE); + when(mapMock.containsKey("X-Amz-Target")).thenReturn(true); + when(mapMock.get("X-Amz-Target")).thenReturn("list queues"); //call awsLatencyRequestHandler.beforeRequest(request); @@ -63,13 +117,17 @@ public void testWithGoodRequestId() throws InterruptedException { awsLatencyRequestHandler.afterResponse(request, response); //verify - verify(request, times(2)).getHeaders(); - verify(response, times(2)).getHttpResponse(); + verify(request, times(5)).getHeaders(); + verify(response, times(5)).getHttpResponse(); verify(request, times(1)).getHttpMethod(); - verify(request, times(1)).getServiceName(); + verify(request, times(2)).getServiceName(); verify(httpResponse, times(1)).getStatusCode(); + verify(httpResponse, times(2)).getHeaders(); verify(mapMock, times(1)).put(anyString(), anyString()); - verify(mapMock, times(1)).get(anyString()); + verify(mapMock, times(1)).get("requestId"); + verify(mapMock, times(1)).get("x-amzn-RequestId"); + verify(mapMock, times(1)).get("X-Amz-Target"); + verify(mapMock, times(1)).containsKey("X-Amz-Target"); verifyNoMoreInteractions(request); verifyNoMoreInteractions(httpResponse); verifyNoMoreInteractions(mapMock); @@ -84,6 +142,59 @@ public void testWithGoodRequestId() throws InterruptedException { assertEquals(200, httpResponse.getStatusCode()); } + @Test + public void testWithGoodRequestIdS3Service() throws InterruptedException { + + //setup + Request request = mock(Request.class); + Response response = PowerMockito.mock(Response.class); + HttpResponse httpResponse = mock(HttpResponse.class); + Map mapMock = mock(Map.class); + mockStatic(RandomGenerator.class); + + when(request.getServiceName()).thenReturn("Amazon S3"); + when(request.getHttpMethod()).thenReturn(HttpMethodName.GET); + when(RandomGenerator.getUUIDRandomString()).thenReturn(REQUEST_VALUE); + when(request.getHeaders()).thenReturn(mapMock); + when(response.getHttpResponse()).thenReturn(httpResponse); + when(httpResponse.getStatusCode()).thenReturn(200); + when(httpResponse.getHeaders()).thenReturn(mapMock); + when(mapMock.get("x-amz-request-id")).thenReturn(REQUEST_VALUE); + when(mapMock.get("x-amz-id-2")).thenReturn("value-2"); + when(mapMock.get("requestId")).thenReturn(REQUEST_VALUE); + + //call + awsLatencyRequestHandler.beforeRequest(request); + Thread.sleep(150); + awsLatencyRequestHandler.afterResponse(request, response); + + //verify + verify(request, times(4)).getHeaders(); + verify(response, times(6)).getHttpResponse(); + verify(request, times(1)).getHttpMethod(); + verify(request, times(2)).getServiceName(); + verify(request, times(2)).getParameters(); + verify(httpResponse, times(1)).getStatusCode(); + verify(httpResponse, times(3)).getHeaders(); + verify(mapMock, times(1)).put(anyString(), anyString()); + verify(mapMock, times(1)).get("requestId"); + verify(mapMock, times(1)).get("x-amz-request-id"); + verify(mapMock, times(1)).get("x-amz-id-2"); + verify(mapMock, times(1)).containsKey("X-Amz-Target"); + verifyNoMoreInteractions(request); + verifyNoMoreInteractions(httpResponse); + verifyNoMoreInteractions(mapMock); + + PowerMockito.verifyStatic(times(1)); + RandomGenerator.getUUIDRandomString(); + PowerMockito.verifyNoMoreInteractions(RandomGenerator.class); + + assertEquals("Amazon S3", request.getServiceName()); + assertEquals(HttpMethodName.GET, request.getHttpMethod()); + assertEquals(REQUEST_VALUE, request.getHeaders().get(REQUEST_ID)); + assertEquals(200, httpResponse.getStatusCode()); + } + @Test public void testRequestIdNotFound() { @@ -93,18 +204,22 @@ public void testRequestIdNotFound() { when(request.getServiceName()).thenReturn("AmazonSQS"); when(request.getHeaders()).thenReturn(mapMock); + when(request.getHttpMethod()).thenReturn(HttpMethodName.GET); when(mapMock.get(REQUEST_ID)).thenReturn(REQUEST_VALUE); + when(mapMock.get("x-amzn-RequestId")).thenReturn(REQUEST_VALUE); //call awsLatencyRequestHandler.beforeRequest(request); awsLatencyRequestHandler.afterResponse(request, null); //verify - verify(request, times(2)).getHeaders(); + verify(request, times(4)).getHeaders(); + verify(request, times(2)).getParameters(); verify(request, times(1)).getHttpMethod(); - verify(request, times(2)).getServiceName(); + verify(request, times(1)).getServiceName(); verify(mapMock, times(1)).put(anyString(), anyString()); verify(mapMock, times(1)).get(anyString()); + verify(mapMock, times(1)).containsKey(anyString()); verifyNoMoreInteractions(request); verifyNoMoreInteractions(mapMock); @@ -122,18 +237,69 @@ public void testResponseNullAfterError() { when(request.getHeaders()).thenReturn(mapMock); when(mapMock.get(REQUEST_ID)).thenReturn(REQUEST_VALUE); when(RandomGenerator.getUUIDRandomString()).thenReturn(REQUEST_VALUE); + when(request.getHttpMethod()).thenReturn(HttpMethodName.GET); + + AmazonServiceException exception = new AmazonServiceException("AmazonServiceException"); + exception.setServiceName("AmazonSQS"); + exception.setStatusCode(500); + exception.setRequestId(REQUEST_VALUE); //call awsLatencyRequestHandler.beforeRequest(request); - awsLatencyRequestHandler.afterError(request, null, new AmazonServiceException("AmazonServiceException")); + awsLatencyRequestHandler.afterError(request, null, exception); //verify - verify(request, times(2)).getHeaders(); + verify(request, times(4)).getHeaders(); + verify(request, times(2)).getParameters(); verify(request, times(1)).getServiceName(); verify(request, times(1)).getHttpMethod(); verify(mapMock, times(1)).put(anyString(), anyString()); verify(mapMock, times(1)).get(anyString()); + verify(mapMock, times(1)).containsKey(anyString()); + + verifyNoMoreInteractions(request); + verifyNoMoreInteractions(mapMock); + + PowerMockito.verifyStatic(times(1)); + RandomGenerator.getUUIDRandomString(); + PowerMockito.verifyNoMoreInteractions(RandomGenerator.class); + } + + @Test + public void testS3ExceptionAfterError() { + + //setup + Request request = mock(Request.class); + Map mapMock = mock(Map.class); + mockStatic(RandomGenerator.class); + + when(request.getServiceName()).thenReturn("Amazon S3"); + when(request.getHeaders()).thenReturn(mapMock); + when(mapMock.get(REQUEST_ID)).thenReturn(REQUEST_VALUE); + when(RandomGenerator.getUUIDRandomString()).thenReturn(REQUEST_VALUE); + when(request.getHttpMethod()).thenReturn(HttpMethodName.GET); + + AmazonS3Exception exception = new AmazonS3Exception("AmazonS3Exception"); + exception.setServiceName("Amazon S3"); + exception.setRequestId(REQUEST_VALUE); + exception.setExtendedRequestId("extended value"); + exception.setStatusCode(500); + exception.setRequestId(REQUEST_VALUE); + + //call + awsLatencyRequestHandler.beforeRequest(request); + awsLatencyRequestHandler.afterError(request, null, exception); + + //verify + verify(request, times(4)).getHeaders(); + verify(request, times(1)).getServiceName(); + verify(request, times(1)).getHttpMethod(); + verify(request, times(2)).getParameters(); + + verify(mapMock, times(1)).put(anyString(), anyString()); + verify(mapMock, times(1)).get(anyString()); + verify(mapMock, times(1)).containsKey(anyString()); verifyNoMoreInteractions(request); verifyNoMoreInteractions(mapMock); @@ -155,25 +321,31 @@ public void testResponseNotNullAfterError() { when(request.getServiceName()).thenReturn("AmazonSQS"); when(RandomGenerator.getUUIDRandomString()).thenReturn(REQUEST_VALUE); + when(request.getHttpMethod()).thenReturn(HttpMethodName.GET); when(request.getHeaders()).thenReturn(mapMock); when(mapMock.get(REQUEST_ID)).thenReturn(REQUEST_VALUE); when(response.getHttpResponse()).thenReturn(httpResponse); - when(httpResponse.getStatusCode()).thenReturn(200); + when(httpResponse.getStatusCode()).thenReturn(403); + AmazonServiceException exception = new AmazonServiceException("AmazonServiceException"); + exception.setServiceName("AmazonSQS"); + exception.setStatusCode(403); + exception.setRequestId(REQUEST_VALUE); + exception.setErrorCode("403"); //call awsLatencyRequestHandler.beforeRequest(request); - AmazonServiceException exception = new AmazonServiceException("AmazonServiceException"); - exception.setErrorCode("403"); awsLatencyRequestHandler.afterError(request, response, exception); //verify - verify(request, times(2)).getHeaders(); + verify(request, times(4)).getHeaders(); + verify(request, times(2)).getParameters(); verify(request, times(1)).getHttpMethod(); verify(request, times(1)).getServiceName(); verify(response, times(2)).getHttpResponse(); verify(httpResponse, times(1)).getStatusCode(); verify(mapMock, times(1)).put(anyString(), anyString()); verify(mapMock, times(1)).get(anyString()); + verify(mapMock, times(1)).containsKey(anyString()); verifyNoMoreInteractions(request); verifyNoMoreInteractions(response); @@ -197,19 +369,24 @@ public void testResponseWithClientException() { when(request.getServiceName()).thenReturn("AmazonSQS"); when(RandomGenerator.getUUIDRandomString()).thenReturn(REQUEST_VALUE); when(request.getHeaders()).thenReturn(mapMock); + when(request.getHttpMethod()).thenReturn(HttpMethodName.GET); when(mapMock.get(REQUEST_ID)).thenReturn(REQUEST_VALUE); when(response.getHttpResponse()).thenReturn(null); + AmazonClientException exception = new AmazonClientException("AmazonClientException"); //call awsLatencyRequestHandler.beforeRequest(request); - awsLatencyRequestHandler.afterError(request, null, new AmazonClientException("AmazonClientException")); + + awsLatencyRequestHandler.afterError(request, null, exception); //verify - verify(request, times(2)).getHeaders(); + verify(request, times(4)).getHeaders(); + verify(request, times(2)).getParameters(); verify(request, times(1)).getHttpMethod(); verify(request, times(1)).getServiceName(); verify(mapMock, times(1)).put(anyString(), anyString()); verify(mapMock, times(1)).get(anyString()); + verify(mapMock, times(1)).containsKey(anyString()); verifyNoMoreInteractions(request); verifyNoMoreInteractions(response);