package rocks.inspectit.agent.java.sensor.method.http;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.lang.management.ThreadMXBean;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.collections.MapUtils;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import rocks.inspectit.agent.java.AbstractLogSupport;
import rocks.inspectit.agent.java.config.impl.RegisteredSensorConfig;
import rocks.inspectit.agent.java.core.ICoreService;
import rocks.inspectit.agent.java.core.IPlatformManager;
import rocks.inspectit.agent.java.util.Timer;
import rocks.inspectit.shared.all.communication.MethodSensorData;
import rocks.inspectit.shared.all.communication.data.HttpTimerData;
/**
* Tests the {@link HttpHook} class.
*
*/
@SuppressWarnings("PMD")
public class HttpHookTest extends AbstractLogSupport {
@Mock
private Timer timer;
@Mock
private IPlatformManager platformManager;
@Mock
private ICoreService coreService;
@Mock
private RegisteredSensorConfig registeredSensorConfig;
@Mock
private ThreadMXBean threadMXBean;
@Mock
private Object result;
@Mock
private HttpServlet servlet;
@Mock
private HttpServletRequest httpServletRequest;
@Mock
private HttpServletResponse httpServletResponse;
@Mock
private ServletRequest servletRequest;
@Mock
private ServletRequest servletResponse;
@Mock
private HttpSession session;
private HttpHook httpHook;
private final long platformId = 1L;
private final long methodId = 1L;
private final long sensorTypeId = 3L;
@BeforeMethod
public void initTestClass() {
Map<String, String> settings = new HashMap<String, String>();
settings.put("sessioncapture", "false");
when(threadMXBean.isThreadCpuTimeEnabled()).thenReturn(true);
when(threadMXBean.isThreadCpuTimeSupported()).thenReturn(true);
Map<String, Object> map = new HashMap<String, Object>();
MapUtils.putAll(map, new String[][] { { "sessioncapture", "true" } });
httpHook = new HttpHook(timer, platformManager, map, threadMXBean);
}
@Test
public void oneRecordThatIsHttpWithoutReadingData() {
Double firstTimerValue = 1000.453d;
Double secondTimerValue = 1323.675d;
Long firstCpuTimerValue = 5000L;
Long secondCpuTimerValue = 6872L;
HttpTimerData data = new HttpTimerData(null, platformId, sensorTypeId, methodId);
when(timer.getCurrentTime()).thenReturn(firstTimerValue).thenReturn(secondTimerValue);
when(threadMXBean.getCurrentThreadCpuTime()).thenReturn(firstCpuTimerValue).thenReturn(secondCpuTimerValue);
when(platformManager.getPlatformId()).thenReturn(platformId);
Object[] parameters = new Object[] { httpServletRequest, httpServletResponse };
httpHook.beforeBody(methodId, sensorTypeId, servlet, parameters, registeredSensorConfig);
httpHook.firstAfterBody(methodId, sensorTypeId, servlet, parameters, result, registeredSensorConfig);
httpHook.secondAfterBody(coreService, methodId, sensorTypeId, servlet, parameters, result, registeredSensorConfig);
verify(coreService).addMethodSensorData(eq(sensorTypeId), eq(methodId), eq(String.valueOf(firstTimerValue)), argThat(new HttpTimerDataVerifier(data)));
verifyZeroInteractions(result);
}
@Test
public void oneRecordThatIsHttpCharting() {
Double firstTimerValue = 1000.453d;
Double secondTimerValue = 1323.675d;
Long firstCpuTimerValue = 5000L;
Long secondCpuTimerValue = 6872L;
HttpTimerData data = new HttpTimerData(null, platformId, sensorTypeId, methodId);
data.setCharting(true);
when(timer.getCurrentTime()).thenReturn(firstTimerValue).thenReturn(secondTimerValue);
when(threadMXBean.getCurrentThreadCpuTime()).thenReturn(firstCpuTimerValue).thenReturn(secondCpuTimerValue);
when(platformManager.getPlatformId()).thenReturn(platformId);
when(registeredSensorConfig.getSettings()).thenReturn(Collections.<String, Object> singletonMap("charting", Boolean.TRUE));
Object[] parameters = new Object[] { httpServletRequest, httpServletResponse };
httpHook.beforeBody(methodId, sensorTypeId, servlet, parameters, registeredSensorConfig);
httpHook.firstAfterBody(methodId, sensorTypeId, servlet, parameters, result, registeredSensorConfig);
httpHook.secondAfterBody(coreService, methodId, sensorTypeId, servlet, parameters, result, registeredSensorConfig);
verify(coreService).addMethodSensorData(eq(sensorTypeId), eq(methodId), eq(String.valueOf(firstTimerValue)), argThat(new HttpTimerDataVerifier(data)));
verifyZeroInteractions(result);
}
@Test
public void oneRecordThatIsHttpReadingDataNoCropping() {
final String uri = "URI";
final String method = "GET";
final String param1 = "p1";
final String param2 = "p2";
final String param1VReal = "value1";
final String param2VReal1 = "value5";
final String param2VReal2 = "value6";
final String[] param1V = new String[] { param1VReal };
final String[] param2V = new String[] { param2VReal1, param2VReal2 };
final Map<String, String[]> parameterMap = new HashMap<String, String[]>();
MapUtils.putAll(parameterMap, new Object[][] { { param1, param1V }, { param2, param2V } });
final String att1 = "a1";
final String att2 = "a2";
final String att1Value = "aValue1";
final String att2Value = "aValue2";
final Vector<String> attributesList = new Vector<String>();
Collections.addAll(attributesList, att1, att2);
final Enumeration<String> attributes = attributesList.elements();
final String h1 = "h1";
final String h2 = "h2";
final String h1Value = "hValue1";
final String h2Value = "hValue2";
final Vector<String> headersList = new Vector<String>();
Collections.addAll(headersList, h1, h2);
final Enumeration<String> headers = headersList.elements();
final String sa1 = "sa1";
final String sa2 = "sa2";
final String sa1Value = "saValue1";
final String sa2Value = "saValue2";
final Vector<String> sessionAttributesList = new Vector<String>();
Collections.addAll(sessionAttributesList, sa1, sa2);
final Enumeration<String> sessionAttributes = sessionAttributesList.elements();
Double firstTimerValue = 1000.453d;
Double secondTimerValue = 1323.675d;
Long firstCpuTimerValue = 5000L;
Long secondCpuTimerValue = 6872L;
HttpTimerData tmp = new HttpTimerData(null, platformId, sensorTypeId, methodId);
tmp.getHttpInfo().setRequestMethod(method);
tmp.getHttpInfo().setUri(uri);
Map<String, String> attributeMap = new HashMap<String, String>();
MapUtils.putAll(attributeMap, new Object[][] { { att1, att1Value }, { att2, att2Value } });
tmp.setAttributes(attributeMap);
tmp.setParameters(parameterMap);
Map<String, String> headerMap = new HashMap<String, String>();
MapUtils.putAll(headerMap, new Object[][] { { h1, h1Value }, { h2, h2Value } });
tmp.setHeaders(headerMap);
Map<String, String> sessionAtrMap = new HashMap<String, String>();
MapUtils.putAll(sessionAtrMap, new Object[][] { { sa1, sa1Value }, { sa2, sa2Value } });
tmp.setSessionAttributes(sessionAtrMap);
int responseStatus = 404;
tmp.setHttpResponseStatus(responseStatus);
MethodSensorData data = tmp;
when(timer.getCurrentTime()).thenReturn(firstTimerValue).thenReturn(secondTimerValue);
when(threadMXBean.getCurrentThreadCpuTime()).thenReturn(firstCpuTimerValue).thenReturn(secondCpuTimerValue);
when(platformManager.getPlatformId()).thenReturn(platformId);
when(httpServletRequest.getMethod()).thenReturn(method);
when(httpServletRequest.getRequestURI()).thenReturn(uri);
when(httpServletRequest.getParameterMap()).thenReturn(parameterMap);
when(httpServletRequest.getAttributeNames()).thenReturn(attributes);
when(httpServletRequest.getAttribute(att1)).thenReturn(att1Value);
when(httpServletRequest.getAttribute(att2)).thenReturn(att2Value);
when(httpServletRequest.getHeaderNames()).thenReturn(headers);
when(httpServletRequest.getHeader(h1)).thenReturn(h1Value);
when(httpServletRequest.getHeader(h2)).thenReturn(h2Value);
when(httpServletResponse.getStatus()).thenReturn(responseStatus);
when(session.getAttributeNames()).thenReturn(sessionAttributes);
when(session.getAttribute(sa1)).thenReturn(sa1Value);
when(session.getAttribute(sa2)).thenReturn(sa2Value);
when(httpServletRequest.getSession(false)).thenReturn(session);
// Object servlet = (Object) new MyTestServlet();
Object[] parameters = new Object[] { httpServletRequest, httpServletResponse };
httpHook.beforeBody(methodId, sensorTypeId, servlet, parameters, registeredSensorConfig);
httpHook.firstAfterBody(methodId, sensorTypeId, servlet, parameters, result, registeredSensorConfig);
httpHook.secondAfterBody(coreService, methodId, sensorTypeId, servlet, parameters, result, registeredSensorConfig);
verify(coreService).addMethodSensorData(eq(sensorTypeId), eq(methodId), eq(String.valueOf(firstTimerValue)), argThat(new HttpTimerDataVerifier((HttpTimerData) data)));
verifyZeroInteractions(result);
}
@Test
public void oneRecordThatIsNotHttp() {
Double firstTimerValue = 1000.453d;
Double secondTimerValue = 1323.675d;
Long firstCpuTimerValue = 5000L;
Long secondCpuTimerValue = 6872L;
when(timer.getCurrentTime()).thenReturn(firstTimerValue).thenReturn(secondTimerValue);
when(threadMXBean.getCurrentThreadCpuTime()).thenReturn(firstCpuTimerValue).thenReturn(secondCpuTimerValue);
when(platformManager.getPlatformId()).thenReturn(platformId);
Object[] parameters = new Object[] { servletRequest, servletResponse };
httpHook.beforeBody(methodId, sensorTypeId, servlet, parameters, registeredSensorConfig);
httpHook.firstAfterBody(methodId, sensorTypeId, servlet, parameters, result, registeredSensorConfig);
httpHook.secondAfterBody(coreService, methodId, sensorTypeId, servlet, parameters, result, registeredSensorConfig);
// Data must not be pushed!
verifyNoMoreInteractions(coreService);
verifyZeroInteractions(result);
}
@Test
public void twoInvocationsAfterEachOther() {
// Idea: Is it also working for two invocations after each other. Is the marker reset
// correctly?
// First invocation:
// a) has no http
// b) has http
// Seconf invocation:
// a) has http
// b) has no http
// initialize the ids
long platformId = 1L;
long sensorTypeId = 3L;
long methodId11 = 1L;
long methodId12 = 2L;
long methodId21 = 3L;
long methodId22 = 4L;
Double timerS11 = 1000d;
Double timerS12 = 1500d;
Double timerE12 = 2000d;
Double timerE11 = 2500d;
Double timerS21 = 2000d;
Double timerS22 = 2500d;
Double timerE22 = 3000d;
Double timerE21 = 3500d;
Long cpuS11 = 11000L;
Long cpuS12 = 21500L;
Long cpuE12 = 34500L;
Long cpuE11 = 45000L;
Long cpuS21 = 52000L;
Long cpuS22 = 62500L;
Long cpuE22 = 73500L;
Long cpuE21 = 84000L;
// The second one should have the results!
MethodSensorData data1 = new HttpTimerData(null, platformId, sensorTypeId, methodId12);
MethodSensorData data2 = new HttpTimerData(null, platformId, sensorTypeId, methodId21);
when(timer.getCurrentTime()).thenReturn(timerS11).thenReturn(timerS12).thenReturn(timerE12).thenReturn(timerE11).thenReturn(timerS21).thenReturn(timerS22).thenReturn(timerE22)
.thenReturn(timerE21);
when(threadMXBean.getCurrentThreadCpuTime()).thenReturn(cpuS11).thenReturn(cpuS12).thenReturn(cpuE12).thenReturn(cpuE11).thenReturn(cpuS21).thenReturn(cpuS22).thenReturn(cpuE22)
.thenReturn(cpuE21);
when(platformManager.getPlatformId()).thenReturn(platformId);
Object[] parametersNoHttp = new Object[] { servletRequest, servletResponse };
Object[] parametersHttp = new Object[] { httpServletRequest, httpServletResponse };
httpHook.beforeBody(methodId11, sensorTypeId, servlet, parametersNoHttp, registeredSensorConfig);
httpHook.beforeBody(methodId12, sensorTypeId, servlet, parametersHttp, registeredSensorConfig);
httpHook.firstAfterBody(methodId12, sensorTypeId, servlet, parametersHttp, result, registeredSensorConfig);
httpHook.secondAfterBody(coreService, methodId12, sensorTypeId, servlet, parametersHttp, result, registeredSensorConfig);
httpHook.firstAfterBody(methodId11, sensorTypeId, servlet, parametersNoHttp, result, registeredSensorConfig);
httpHook.secondAfterBody(coreService, methodId11, sensorTypeId, servlet, parametersNoHttp, result, registeredSensorConfig);
verify(coreService).addMethodSensorData(eq(sensorTypeId), eq(methodId12), eq(String.valueOf(timerS11)), argThat(new HttpTimerDataVerifier((HttpTimerData) data1)));
httpHook.beforeBody(methodId21, sensorTypeId, servlet, parametersHttp, registeredSensorConfig);
httpHook.beforeBody(methodId22, sensorTypeId, servlet, parametersNoHttp, registeredSensorConfig);
httpHook.firstAfterBody(methodId22, sensorTypeId, servlet, parametersNoHttp, result, registeredSensorConfig);
httpHook.secondAfterBody(coreService, methodId22, sensorTypeId, servlet, parametersNoHttp, result, registeredSensorConfig);
httpHook.firstAfterBody(methodId21, sensorTypeId, servlet, parametersHttp, result, registeredSensorConfig);
httpHook.secondAfterBody(coreService, methodId21, sensorTypeId, servlet, parametersHttp, result, registeredSensorConfig);
verify(coreService).addMethodSensorData(eq(sensorTypeId), eq(methodId21), eq(String.valueOf(timerE12)), argThat(new HttpTimerDataVerifier((HttpTimerData) data2)));
// ensure that there are no exceptions (like "NoSuchElement" which means that before or
// after did not push a timer object)
// No other data must not be pushed!
verifyNoMoreInteractions(coreService);
verifyZeroInteractions(result);
}
@Test
public void multipleRecordsWithHttp() {
// Idea:
// 1.element -> not http -> no data
// 2.element -> http -> measurement
// 3.element -> not http -> no data
// 4.element -> http -> no data (already have a measurement)
// initialize the ids
long platformId = 1L;
long sensorTypeId = 3L;
long methodId1 = 1L;
long methodId2 = 2L;
long methodId3 = 3L;
long methodId4 = 4L;
Double timerS1 = 1000d;
Double timerS2 = 1500d;
Double timerS3 = 2000d;
Double timerS4 = 2500d;
Double timerE4 = 3500d;
Double timerE3 = 4000d;
Double timerE2 = 4500d;
Double timerE1 = 5000d;
Long cpuS1 = 11000L;
Long cpuS2 = 21500L;
Long cpuS3 = 32000L;
Long cpuS4 = 42500L;
Long cpuE4 = 53500L;
Long cpuE3 = 64000L;
Long cpuE2 = 74500L;
Long cpuE1 = 85000L;
// The second one should have the results!
MethodSensorData data = new HttpTimerData(null, platformId, sensorTypeId, methodId2);
when(timer.getCurrentTime()).thenReturn(timerS1).thenReturn(timerS2).thenReturn(timerS3).thenReturn(timerS4).thenReturn(timerE4).thenReturn(timerE3).thenReturn(timerE2).thenReturn(timerE1);
when(threadMXBean.getCurrentThreadCpuTime()).thenReturn(cpuS1).thenReturn(cpuS2).thenReturn(cpuS3).thenReturn(cpuS4).thenReturn(cpuE4).thenReturn(cpuE3).thenReturn(cpuE2).thenReturn(cpuE1);
when(platformManager.getPlatformId()).thenReturn(platformId);
Object[] parameters1 = new Object[] { servletRequest, servletResponse };
Object[] parameters2 = new Object[] { httpServletRequest, httpServletResponse };
Object[] parameters3 = new Object[] { "Ich bin ein String und keine http information" };
Object[] parameters4 = new Object[] { httpServletRequest, httpServletResponse };
httpHook.beforeBody(methodId1, sensorTypeId, servlet, parameters1, registeredSensorConfig);
httpHook.beforeBody(methodId2, sensorTypeId, servlet, parameters2, registeredSensorConfig);
httpHook.beforeBody(methodId3, sensorTypeId, servlet, parameters3, registeredSensorConfig);
httpHook.beforeBody(methodId4, sensorTypeId, servlet, parameters4, registeredSensorConfig);
httpHook.firstAfterBody(methodId4, sensorTypeId, servlet, parameters4, result, registeredSensorConfig);
httpHook.secondAfterBody(coreService, methodId4, sensorTypeId, servlet, parameters4, result, registeredSensorConfig);
httpHook.firstAfterBody(methodId3, sensorTypeId, servlet, parameters3, result, registeredSensorConfig);
httpHook.secondAfterBody(coreService, methodId3, sensorTypeId, servlet, parameters3, result, registeredSensorConfig);
httpHook.firstAfterBody(methodId2, sensorTypeId, servlet, parameters2, result, registeredSensorConfig);
httpHook.secondAfterBody(coreService, methodId2, sensorTypeId, servlet, parameters2, result, registeredSensorConfig);
httpHook.firstAfterBody(methodId1, sensorTypeId, servlet, parameters1, result, registeredSensorConfig);
httpHook.secondAfterBody(coreService, methodId1, sensorTypeId, servlet, parameters1, result, registeredSensorConfig);
verify(coreService).addMethodSensorData(eq(sensorTypeId), eq(methodId2), eq(String.valueOf(timerS1)), argThat(new HttpTimerDataVerifier((HttpTimerData) data)));
// No other data must not be pushed!
verifyNoMoreInteractions(coreService);
verifyZeroInteractions(result);
}
/**
* Inner class used to verify the contents of PlainTimerData objects.
*/
private static class HttpTimerDataVerifier extends ArgumentMatcher<HttpTimerData> {
private final HttpTimerData data;
public HttpTimerDataVerifier(HttpTimerData data) {
this.data = data;
}
@Override
public boolean matches(Object object) {
if (!HttpTimerData.class.isInstance(object)) {
return false;
}
HttpTimerData other = (HttpTimerData) object;
assertThat(data.getHttpInfo().getUri(), is(equalTo(other.getHttpInfo().getUri())));
assertThat(data.getHttpInfo().getRequestMethod(), is(equalTo(other.getHttpInfo().getRequestMethod())));
assertThat(data.getAttributes(), is(equalTo(other.getAttributes())));
assertThat(data.getHeaders(), is(equalTo(other.getHeaders())));
assertThat(data.getSessionAttributes(), is(equalTo(other.getSessionAttributes())));
assertThat(data.getParameters(), is(equalTo(other.getParameters())));
assertThat(data.isCharting(), is(equalTo(other.isCharting())));
assertThat(data.getHttpResponseStatus(), is(equalTo(other.getHttpResponseStatus())));
return true;
}
}
}