package com.rackspacecloud.blueflood.outputs.handlers; import com.rackspacecloud.blueflood.exceptions.SerializationException; import com.rackspacecloud.blueflood.outputs.formats.ErrorResponse; import com.rackspacecloud.blueflood.outputs.formats.MetricData; import com.rackspacecloud.blueflood.outputs.serializers.BasicRollupsOutputSerializer; import com.rackspacecloud.blueflood.outputs.serializers.BatchedMetricsJSONOutputSerializer; import com.rackspacecloud.blueflood.service.Configuration; import com.rackspacecloud.blueflood.service.HttpConfig; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; import org.json.simple.JSONObject; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import java.io.IOException; import java.nio.charset.Charset; import java.util.Map; import static junit.framework.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyMap; import static org.mockito.Matchers.anySet; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class HttpMultiRollupsQueryHandlerTest extends HandlerTestsBase { private HttpMultiRollupsQueryHandler handler; private static final String TENANT = "tenant"; private ChannelHandlerContext context; private Channel channel; private BatchedMetricsJSONOutputSerializer serializer; @Before public void setup() { serializer = mock(BatchedMetricsJSONOutputSerializer.class); handler = new HttpMultiRollupsQueryHandler(serializer); channel = mock(Channel.class); context = mock(ChannelHandlerContext.class); when(context.channel()).thenReturn(channel); } @Test public void testWithNoRequestBody() throws IOException { FullHttpRequest request = createQueryRequest("", ""); ArgumentCaptor<FullHttpResponse> argument = ArgumentCaptor.forClass(FullHttpResponse.class); handler.handle(context, request); verify(channel).write(argument.capture()); String errorResponseBody = argument.getValue().content().toString(Charset.defaultCharset()); ErrorResponse errorResponse = getErrorResponse(errorResponseBody); assertEquals("Number of errors invalid", 1, errorResponse.getErrors().size()); assertEquals("Invalid error message", "Invalid body. Expected JSON array of metrics.", errorResponse.getErrors().get(0).getMessage()); assertEquals("Invalid tenant", TENANT, errorResponse.getErrors().get(0).getTenantId()); assertEquals("Invalid status", HttpResponseStatus.BAD_REQUEST, argument.getValue().getStatus()); } @Test public void testWithTooMayLocatorsInRequestBody() throws IOException { int maxLimit = Configuration.getInstance().getIntegerProperty(HttpConfig.MAX_METRICS_PER_BATCH_QUERY); FullHttpRequest request = createQueryRequest("", createRequestBody(maxLimit + 1)); ArgumentCaptor<FullHttpResponse> argument = ArgumentCaptor.forClass(FullHttpResponse.class); handler.handle(context, request); verify(channel).write(argument.capture()); String errorResponseBody = argument.getValue().content().toString(Charset.defaultCharset()); ErrorResponse errorResponse = getErrorResponse(errorResponseBody); assertEquals("Number of errors invalid", 1, errorResponse.getErrors().size()); assertEquals("Invalid error message", "Too many metrics fetch in a single call. Max limit is " + maxLimit + ".", errorResponse.getErrors().get(0).getMessage()); assertEquals("Invalid tenant", TENANT, errorResponse.getErrors().get(0).getTenantId()); assertEquals("Invalid status", HttpResponseStatus.BAD_REQUEST, argument.getValue().getStatus()); } @Test public void testWithNoQueryParams() throws IOException { FullHttpRequest request = createQueryRequest("", createRequestBody(1)); ArgumentCaptor<FullHttpResponse> argument = ArgumentCaptor.forClass(FullHttpResponse.class); handler.handle(context, request); verify(channel).write(argument.capture()); String errorResponseBody = argument.getValue().content().toString(Charset.defaultCharset()); ErrorResponse errorResponse = getErrorResponse(errorResponseBody); assertEquals("Number of errors invalid", 1, errorResponse.getErrors().size()); assertEquals("Invalid error message", "No query parameters present.", errorResponse.getErrors().get(0).getMessage()); assertEquals("Invalid tenant", TENANT, errorResponse.getErrors().get(0).getTenantId()); assertEquals("Invalid status", HttpResponseStatus.BAD_REQUEST, argument.getValue().getStatus()); } @Test public void testMissingRequiredQueryParams() throws IOException { FullHttpRequest request = createQueryRequest("?from=111111", createRequestBody(1)); ArgumentCaptor<FullHttpResponse> argument = ArgumentCaptor.forClass(FullHttpResponse.class); handler.handle(context, request); verify(channel).write(argument.capture()); String errorResponseBody = argument.getValue().content().toString(Charset.defaultCharset()); ErrorResponse errorResponse = getErrorResponse(errorResponseBody); assertEquals("Number of errors invalid", 1, errorResponse.getErrors().size()); assertEquals("Invalid error message", "Either 'points' or 'resolution' is required.", errorResponse.getErrors().get(0).getMessage()); assertEquals("Invalid tenant", TENANT, errorResponse.getErrors().get(0).getTenantId()); assertEquals("Invalid status", HttpResponseStatus.BAD_REQUEST, argument.getValue().getStatus()); } @Test public void testRequestWithSerializationException() throws IOException { FullHttpRequest request = createQueryRequest("?points=10&from=1&to=2", createRequestBody(1)); ArgumentCaptor<FullHttpResponse> argument = ArgumentCaptor.forClass(FullHttpResponse.class); String message = "mock exception message"; when(serializer.transformRollupData(anyMap(), anySet())).thenThrow(new SerializationException(message)); handler.handle(context, request); verify(channel).write(argument.capture()); String errorResponseBody = argument.getValue().content().toString(Charset.defaultCharset()); ErrorResponse errorResponse = getErrorResponse(errorResponseBody); assertEquals("Number of errors invalid", 1, errorResponse.getErrors().size()); assertEquals("Invalid error message", message, errorResponse.getErrors().get(0).getMessage()); assertEquals("Invalid tenant", TENANT, errorResponse.getErrors().get(0).getTenantId()); assertEquals("Invalid status", HttpResponseStatus.INTERNAL_SERVER_ERROR, argument.getValue().getStatus()); } private String createRequestBody(int batchSize) { StringBuilder sb = new StringBuilder(); sb.append("["); for (int i =0; i < batchSize; i ++) { sb.append("\'metric" + i + "\'"); sb.append(","); } sb.deleteCharAt(sb.length() - 1); sb.append("]"); return sb.toString(); } private FullHttpRequest createQueryRequest(String queryParams, String requestBody) { return super.createPostRequest("/v2.0/" + TENANT + "/views/" + queryParams, requestBody); } }